[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-83849":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":13,"stars7d":17,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":28,"readmeContent":29,"aiSummary":10,"trendingCount":16,"starSnapshotCount":16,"syncStatus":30,"lastSyncTime":31,"discoverSource":32},83849,"OpenCode-goal-plugin","willytop8\u002FOpenCode-goal-plugin","willytop8","adds \u002Fgoal functionality similar to that used in Codex and Claude Code to OpenCode. ","",null,"JavaScript",76,7,52,1,0,22,32,69.91,"MIT License",false,"main",true,[25,26,27],"goals","opencode","opencode-plugin","2026-06-12 04:01:42","# opencode-goal-plugin\n\nAn experimental session-scoped `\u002Fgoal` command for [OpenCode](https:\u002F\u002Fopencode.ai\u002F).\n\nSet a goal and the plugin keeps it in context, auto-continues the session whenever the assistant goes idle, and stops when the goal is marked complete, a blocker is reported, or a safety limit is reached.\n\nCompatibility: this plugin relies on experimental OpenCode hooks. Re-test against the exact OpenCode build and provider\u002Fbackend stack you plan to use for unattended work.\n\n## Compatibility snapshot\n\n| Surface | Status |\n|---|---|\n| Node.js | Declared support: `>=18`; CI covers Node 18, 20, and 22 |\n| Package entrypoint | `npm run smoke` verifies the package export path plus `\u002Fgoal` command-hook behavior from a local install without invoking a model |\n| OpenCode host | Manually smoke-tested against OpenCode 1.15.10 using the `opencode-go` provider (`qwen3.7-plus`) on this repo's local hardening branch; re-test your own version\u002Fprovider stack before relying on unattended runs |\n| Provider\u002Fbackend quirks | Strict-template backends require the goal block to merge into the primary `system` message; covered by regression tests |\n\n## Install\n\n```sh\nnpm install opencode-goal-plugin\n```\n\nAdd the plugin and command to your OpenCode config:\n\n```json\n{\n  \"plugin\": [\"opencode-goal-plugin\"],\n  \"command\": {\n    \"goal\": {\n      \"description\": \"Set a session-scoped goal and auto-continue until complete.\",\n      \"template\": \"$ARGUMENTS\",\n      \"agent\": \"build\"\n    }\n  }\n}\n```\n\n## Usage\n\nSet a goal:\n\n```\n\u002Fgoal fix the failing tests and verify the suite passes\n```\n\nOverride limits for a single goal:\n\n```\n\u002Fgoal fix the failing tests --max-turns 20 --max-minutes 30 --max-tokens 400000\n```\n\nFlags accept either `--flag value` or `--flag=value`. If a flag is unknown, missing a value, or given a non-positive integer, the plugin rejects the command with a helpful error instead of silently folding the bad flag into the goal text.\n\nCheck status:\n\n```\n\u002Fgoal status\n```\n\nView lifecycle history and the latest checkpoint:\n\n```\n\u002Fgoal history\n```\n\nResume a paused or stopped goal:\n\n```\n\u002Fgoal resume\n```\n\nPause without clearing the active goal:\n\n```\n\u002Fgoal pause\n```\n\nClear the active goal:\n\n```\n\u002Fgoal clear\n```\n\n`\u002Fgoal stop`, `\u002Fgoal off`, `\u002Fgoal reset`, `\u002Fgoal none`, and `\u002Fgoal cancel` are aliases for `\u002Fgoal clear`.\n\n## How it works\n\n1. When you set a goal, the plugin stores it in session memory and injects it into the system prompt so the assistant keeps it in view on every turn.\n2. Each time the session goes idle, the plugin sends a continuation prompt containing the goal, the remaining budget, and a completion audit asking the assistant to verify the current state before declaring done.\n3. The plugin stops auto-continuing when the assistant ends a response with `[goal:complete]` or `[goal:blocked]`, or when a safety limit is reached.\n\n## Completion markers\n\nThe plugin stops when it sees one of these at the end of an assistant response:\n\n```\n[goal:complete]\n[goal:blocked]\n```\n\n`[goal:complete]` — goal is satisfied.\n`[goal:blocked]` — the assistant needs input from you. The line immediately before the marker explains the specific blocker; `\u002Fgoal status` shows it while the goal remains in memory.\n\nMarkers must appear on their own final line. The bracketed form is canonical, but the plugin also accepts bare `goal:complete` and `goal:blocked` final lines because some models omit brackets. Natural-language phrases like \"goal complete\" are intentionally ignored.\n\n## Safety limits\n\n| Limit | Default |\n|---|---|\n| Auto-continue turns | 10 |\n| Max duration | 15 minutes |\n| Tracked tokens | 200,000 |\n| Min delay between continues | 1.5 seconds |\n| No-progress pause | \u003C 50 output tokens on a stalled turn (after a 2-turn grace window) |\n| Budget wrap-up threshold | 80% of tracked token budget |\n| Auto-continue failure pause | 3 consecutive prompt failures |\n\n**Effective turn count.** Each LLM turn on a real task typically takes 30–90 seconds. At that latency, raising `--max-minutes` is usually more useful than raising `--max-turns`. At 45 s\u002Fturn, the default 15-minute window gives roughly 15–20 turns of headroom before the turn limit becomes the binding brake.\n\n**Token budget.** The plugin tracks `input + output + reasoning` tokens across all session messages. In high-context sessions (large codebases, long conversation history), input overhead per turn can be substantial and the budget may be exhausted before the turn limit is reached. Treat it as a safety brake, not precise billing accounting.\n\n**No-progress heuristic.** A low-output turn does not pause immediately anymore. The plugin pauses only after `noProgressTurnsBeforePause` consecutive *stalled* low-output turns — repeated turns with very little output and no meaningful change in the latest assistant checkpoint.\n\n**Wrap-up vs. hard stop.** When a limit is reached, the plugin sends one final prompt asking the assistant to summarize what is done, what remains, and the next concrete step — rather than stopping silently. Use `\u002Fgoal resume` to continue after any stop, including limit stops and no-progress pauses.\n\nGoal state is persisted by default to `~\u002F.opencode-goal-plugin\u002Fstate.json`, but only as a local workflow checkpoint. It is not synchronized across machines or OpenCode instances.\n\nThe state directory is created with owner-only permissions, and the JSON state file is written as `0600` because it may contain goal text, assistant checkpoints, and workflow history.\n\nRecovered active goals are loaded in a **paused** state with a recovery note, so unattended auto-continue does not resume blindly after a restart. Set `\"persistState\": false` to keep purely in-memory behavior.\n\n`\u002Fgoal resume` continues the same objective with a fresh local budget window. This lets you continue after pause, blocker, no-progress pause, rate-limit failures, or a limit stop without retyping the objective.\n\n### Per-goal flags\n\nOverride any limit for a single goal:\n\n| Flag | Controls |\n|---|---|\n| `--max-turns \u003Cn>` | Auto-continue turn limit |\n| `--max-minutes \u003Cn>` | Duration limit in minutes |\n| `--max-duration-ms \u003Cn>` | Duration limit in milliseconds |\n| `--max-tokens \u003Cn>` | Tracked token limit |\n| `--cooldown-ms \u003Cn>` | Minimum delay between continues |\n| `--no-progress-threshold \u003Cn>` | Output token floor before pausing |\n| `--no-progress-turns \u003Cn>` | Consecutive stalled low-output turns before pausing |\n\nExamples:\n\n```sh\n\u002Fgoal fix tests --max-turns 20 --max-tokens 400000\n\u002Fgoal fix tests --max-turns=20 --max-tokens=400000\n\u002Fgoal fix tests --no-progress-threshold 50 --no-progress-turns 2\n```\n\n### Plugin-level defaults\n\nPass options when registering the plugin to change the defaults for all goals. To combine with the `goal` command, merge this plugin entry into the config shown above.\n\n```json\n{\n  \"plugin\": [\n    [\n      \"opencode-goal-plugin\",\n      {\n        \"maxTurns\": 10,\n        \"maxDurationMs\": 900000,\n        \"maxTokens\": 200000,\n        \"minDelayMs\": 1500,\n        \"maxRecentMessages\": 50,\n        \"noProgressTokenThreshold\": 50,\n        \"noProgressTurnsBeforePause\": 2,\n        \"budgetWrapupRatio\": 0.8,\n        \"maxPromptFailures\": 3,\n        \"persistState\": true,\n        \"stateFilePath\": \"\u002Fhome\u002Fyou\u002F.opencode-goal-plugin\u002Fstate.json\",\n        \"resultRetentionMs\": 604800000,\n        \"maxStoredResults\": 200\n      }\n    ]\n  ]\n}\n```\n\nAdditional plugin-level options:\n\n- `maxRecentMessages` — how many recent session messages to scan when looking for the latest assistant turn before auto-continuing. Higher values make long, tool-heavy sessions less likely to lose the most recent assistant response.\n- `noProgressTurnsBeforePause` — grace window for low-output stalls. The plugin pauses only after this many consecutive stalled low-output turns rather than on the first one.\n- `persistState` — whether to persist active goals and recent goal results to disk.\n- `stateFilePath` — where the persisted state JSON is written. Useful if you want per-project or ephemeral storage.\n- `resultRetentionMs` — how long a completed goal summary remains available through `\u002Fgoal status` after the goal leaves active memory.\n- `maxStoredResults` — maximum number of completed-goal summaries retained in process memory before the oldest ones are evicted.\n\n## Prompt safety\n\nThe goal text is wrapped in `\u003Cgoal_objective>` tags and labeled as user-provided task data. The assistant is told to treat it as a task description, not as elevated instructions that can override system, developer, tool, or repository policies.\n\n## Limitations\n\nThis is a marker-based implementation. The assistant is responsible for outputting `[goal:complete]` or `[goal:blocked]` — there is no independent evaluator verifying completion against the original goal. Claude Code's native `\u002Fgoal` uses a separate evaluator model; this plugin currently approximates the workflow using OpenCode hooks and explicit completion markers. A future version could add a separate evaluator once OpenCode exposes a clean plugin API for that flow.\n\nOpenCode's current `command.execute.before` hook does not fully intercept command text. The plugin can update in-memory goal state as a side effect, but the goal text may still be routed into the normal assistant conversation alongside the state update.\n\nThe plugin depends on `experimental.chat.system.transform` and other OpenCode plugin hooks that may change between OpenCode versions.\n\n## Local development\n\nPoint OpenCode at the source file directly for local testing:\n\n```json\n{\n  \"plugin\": [\"file:\u002F\u002F\u002Fabsolute\u002Fpath\u002Fto\u002Fopencode-goal-plugin\u002Fsrc\u002Fgoal-plugin.js\"]\n}\n```\n\nKeep test files outside OpenCode's auto-loaded plugin directory — OpenCode will attempt to load plugin-like files it finds there.\n\n### Smoke-test checklist\n\n1. Run `npm run smoke` to verify the package export path and `\u002Fgoal` command hook without a model call.\n2. Install or file-load the plugin in a temporary OpenCode config.\n3. Add a `goal` command with `\"template\": \"$ARGUMENTS\"`.\n4. Run `\u002Fgoal status` — should report no active goal.\n5. Run `\u002Fgoal inspect this repo and stop immediately with [goal:blocked] if you need user input`.\n6. Verify `\u002Fgoal status`, `\u002Fgoal pause`, `\u002Fgoal resume`, and `\u002Fgoal clear` behave as expected.\n7. If you changed hook payload handling or command behavior, repeat the smoke test against the exact OpenCode version and provider\u002Fbackend combination you care about.\n\n## Development\n\n```sh\nnpm test                # run the test suite\nnpm run test:coverage   # run tests with coverage\nnpm run smoke           # verify package export + command hook without a model call\nnpm run check           # syntax check + tests\nnpm run pack:check      # verify package contents before publishing\n```\n\n## License\n\nMIT\n",2,"2026-06-11 04:11:38","CREATED_QUERY"]