{"id":50793908,"url":"https://github.com/verbalchainsaw/opencode-autogoal","last_synced_at":"2026-06-12T13:00:55.492Z","repository":{"id":363897461,"uuid":"1265455358","full_name":"VerbalChainsaw/opencode-autogoal","owner":"VerbalChainsaw","description":"Keep OpenCode working toward a goal until it's met — conversational goal tools + /goal command + a session.idle auto-loop with deterministic verification.","archived":false,"fork":false,"pushed_at":"2026-06-10T21:10:19.000Z","size":74,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T21:17:53.372Z","etag":null,"topics":["agentic","ai-agent","automation","goal","opencode","opencode-plugin"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/VerbalChainsaw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-10T19:42:45.000Z","updated_at":"2026-06-10T21:10:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/VerbalChainsaw/opencode-autogoal","commit_stats":null,"previous_names":["verbalchainsaw/opencode-autogoal"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/VerbalChainsaw/opencode-autogoal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerbalChainsaw%2Fopencode-autogoal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerbalChainsaw%2Fopencode-autogoal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerbalChainsaw%2Fopencode-autogoal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerbalChainsaw%2Fopencode-autogoal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VerbalChainsaw","download_url":"https://codeload.github.com/VerbalChainsaw/opencode-autogoal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VerbalChainsaw%2Fopencode-autogoal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34245218,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic","ai-agent","automation","goal","opencode","opencode-plugin"],"created_at":"2026-06-12T13:00:28.019Z","updated_at":"2026-06-12T13:00:55.475Z","avatar_url":"https://github.com/VerbalChainsaw.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# opencode-autogoal\n\n[![CI](https://github.com/VerbalChainsaw/opencode-autogoal/actions/workflows/ci.yml/badge.svg)](https://github.com/VerbalChainsaw/opencode-autogoal/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/opencode-autogoal.svg)](https://www.npmjs.com/package/opencode-autogoal)\n[![license](https://img.shields.io/npm/l/opencode-autogoal.svg)](LICENSE)\n\n**Give OpenCode a goal and it keeps working until the goal is met.**\n\nThe easiest way to use it is to **just say what you want** — no syntax to remember:\n\n\u003e **You:** \"Keep working until the tests pass and don't stop on your own.\"\n\u003e **OpenCode:** *(sets the goal itself)* \"Goal set: tests pass — I'll keep going and check after each step. 🎯\"\n\n`opencode-autogoal` adds that behavior to [OpenCode](https://opencode.ai): conversational **tools** (so the agent\nsets and manages goals when you ask in plain English), a `/goal` command if you prefer typing, and a\nbackground auto-loop that re-checks the goal after every turn and nudges the agent onward until the\ncondition holds (or a turn/time limit trips).\n\nDesigned for **OpenCode Desktop (Electron)** and the **terminal** — the engine is a server plugin (what\nDesktop runs). Its only dependency is `@opencode-ai/plugin` (the plugin API your OpenCode already provides).\nAn optional terminal-only dashboard ships alongside.\n\nRequires **OpenCode ≥ 1.16** (uses the `session.idle` and `experimental.session.compacting` hooks).\n\n---\n\n## Install\n\n```bash\nopencode plugin opencode-autogoal\n```\n\nThat single line enables the **conversational tools** — you can immediately say *\"keep going until the\ntests pass\"* and OpenCode sets the goal itself. No command needed.\n\nIf you *also* want the `/goal` slash command, add the `command` block (it makes `/goal` exist; the plugin\nattempts this automatically via the `config` hook too, but declaring it is the reliable path):\n\n```jsonc\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"plugin\": [\"opencode-autogoal\"],\n  \"command\": {\n    \"goal\": {\n      \"description\": \"Set, view, pause, resume, or clear a task goal.\",\n      \"agent\": \"build\",\n      \"template\": \"Process the /goal command with arguments: $ARGUMENTS\"\n    }\n  }\n}\n```\n\n\u003e If your project doesn't use a `build` agent, change `agent` to one you have. See\n\u003e [`examples/opencode.jsonc`](examples/opencode.jsonc).\n\n---\n\n## Usage\n\n### Just talk to it (recommended)\n\nThe plugin gives OpenCode five tools, so you manage goals in plain language — it picks the right one:\n\n| Say something like… | Tool the agent calls |\n|---|---|\n| \"keep going until the tests pass\", \"don't stop until the build is green\" | `set_goal` |\n| \"what's my goal?\", \"how's it going?\" | `goal_status` |\n| \"pause the goal for a sec\" | `pause_goal` |\n| \"ok, back to the goal\" | `resume_goal` |\n| \"stop the goal\", \"we're done with that\" | `clear_goal` |\n\nTip: mention a check command and it's verified deterministically — *\"keep going until `npm test` passes.\"*\n\n\u003e **Note:** the conversational path needs a model that's good at tool-calling (e.g. Claude, GPT-class,\n\u003e strong DeepSeek). Smaller/free models may not invoke `set_goal` from plain English — on those, use the\n\u003e `/goal` command below, which is deterministic on **any** model.\n\n### Or use the `/goal` command (if you prefer typing)\n\n```\n/goal set \"\u003ccondition\u003e\"                 set a goal (the agent starts working immediately)\n/goal set \"\u003ccondition\u003e\" --command \"\u003cc\u003e\" verify completion by running a shell command (exit 0 = met)\n/goal set \"\u003ccondition\u003e\" stop after 10 turns\n/goal                                   show current goal + progress (bare /goal = view)\n/goal pause | resume | clear            control the loop (clear aliases: stop, off, reset, none, cancel)\n/goal template \u003cname\u003e                   set a goal from a built-in or project template\n/goal history                           show recent evaluation results\n```\n\nInline modifiers: `stop after N turns`, `stop after N minutes`, `stop after Nk tokens`,\n`--command \"\u003ccheck\u003e\"` (also `--turns N`, `--time N`). Everything else is the condition.\n\nBoth paths share the same engine and state — use whichever feels natural.\n\n### Examples\n\n```\n/goal set \"all unit tests pass\" --command \"npm test\"\n/goal set \"remove every TODO comment in src/ and explain each removal\" stop after 8 turns\n/goal template fix-lint\n```\n\n### Good to know\n\n- **An active goal steers the conversation.** Until the goal is met, the agent treats it as top priority\n  and gets nudged back to it each turn. Use **`/goal pause`** (or `/goal clear`) before switching to\n  unrelated work. Bare **`/goal`** shows the current status.\n- **The `stop after N …` phrasing is parsed anywhere in the condition.** So `/goal set \"make it stop\n  after 5 turns of retrying\"` would read `5` as a turn limit. For literal text like that, set limits with\n  the unambiguous flags instead (`--turns`, `--time`) and keep them out of the condition prose.\n- **Status commands cost one model turn.** `/goal view|clear|pause|resume|history` are handled by the\n  agent relaying the result, so they aren't instantaneous like a native UI button.\n\n---\n\n## How it works\n\nTwo kinds of goal, two kinds of evaluation:\n\n- **Verifiable goals** (`--command`): after each turn the plugin runs your command in the project\n  directory. **Exit 0 = achieved.** Cross-platform (uses the OS shell), deterministic, the reliable path.\n- **Open-ended goals** (no command): the plugin reads the agent's latest message **read-only** and looks\n  for an explicit completion signal — it never injects evaluation prompts or guesses. The agent declares\n  done with a line beginning `GOAL_COMPLETE:` (and `GOAL_BLOCKED:` if it's stuck). These markers are\n  **line-anchored and code-fence-aware** — the agent merely *talking about* the protocol, or showing an\n  example inside a markdown code block, will not trip the goal. (The detector ignores lines inside\n  ```` ``` ```` or `~~~` fences, and lines indented 4+ spaces — markdown's \"indented code block\"\n  threshold — so the marker is only matched when the agent writes it on its own prose line.)\n\nWhen a goal isn't met yet, one continue-nudge is injected to drive the next turn. Turn and time limits\nstop a runaway loop. On any terminal state (achieved / stopped / blocked) you get a notification **both**\nas a TUI toast (terminal) **and** as a status line in the conversation — the latter is what surfaces on\nDesktop, where TUI toasts don't render.\n\nState lives in `.opencode/.goal-state.json` (atomic writes; auto-gitignored).\n\n### Templates\n\nBuilt-in: `fix-lint`, `fix-types`, `pass-tests`. Add your own at `.opencode/goals/\u003cname\u003e.json`:\n\n```json\n{\n  \"description\": \"Ship the migration\",\n  \"condition\": \"the migration script runs cleanly and the app boots\",\n  \"command\": \"npm run migrate \u0026\u0026 npm run smoke\",\n  \"constraints\": { \"maxTurns\": 20, \"maxTimeMinutes\": 30 }\n}\n```\n\nA project file with the same name overrides a built-in.\n\n---\n\n## Desktop vs. terminal\n\nOpenCode **Desktop (Electron)** is driven entirely by *server* plugins — it does **not** load TUI plugins.\nEverything above works on Desktop via the server plugin. The interactive dashboard below is **terminal-only**.\n\n### Optional terminal dashboard\n\nA small TUI dashboard (`/goal-dashboard`, `/goal-toggle`, `/goal-clear`) ships as `opencode-autogoal/tui`.\nIt is **terminal-only** and **off by default**. Enable it in `tui.json` (only if you run OpenCode in a terminal):\n\n```jsonc\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"plugin\": [\"opencode-autogoal/tui\"]\n}\n```\n\n\u003e ⚠️ The dashboard is shipped best-effort: it type-checks against OpenCode's TUI types and follows the\n\u003e official plugin spec, but verify it in your terminal before relying on it. It has no effect on Desktop.\n\n---\n\n## Development\n\n```bash\nnpm install\nnpm run build       # tsc → dist/ (the server plugin; zero runtime deps)\nnpm test            # build, then run the regression suite (node --test)\nnpm run typecheck   # type-check src/ (server + tui)\n```\n\n- `src/goal-state.ts` — types, arg parsing, atomic state I/O, transitions, marker detection, status formatting, `parseShellWords` (POSIX-style command word splitting for debug diagnostics).\n- `src/command.ts` — the `/goal` dispatcher (pure, deterministic).\n- `src/server.ts` — the plugin wiring: command hook + the auto-loop.\n- `src/tui.tsx` — optional terminal dashboard (shipped as source).\n- `src/tui-logic.ts` — TUI pure logic: validated reads, progress-bar math, toggle/clear. Unit-tested separately from the JSX layer.\n- `src/templates.ts` — built-in goal templates.\n\nThe package ships compiled JS (`dist/`) so it loads regardless of whether the host runtime is Node or Bun.\n\n### What's tested vs. what needs a live check\n\n`npm test` covers `goal-state.ts` and the `/goal` dispatcher (parsing, state, transitions, markers,\nevery command path) against the **built** output. What unit tests *can't* exercise is the live OpenCode\nintegration: the `command.execute.before`/`config` hooks, the `session.idle` loop, and how injected\nmessages render in the Desktop UI. **Smoke-test the packaged tarball before publishing:**\n\n```bash\nnpm pack                                   # builds dist/ and makes opencode-autogoal-x.y.z.tgz\ncd /path/to/a/throwaway/project\nnpm i /path/to/opencode-autogoal-x.y.z.tgz     # exercises the COMPILED output + real install path\n# add the plugin (+ optional command block) to opencode.json, then in OpenCode:\n#   CONVERSATIONAL (primary path):\n#     \"set a goal to write a haiku, then keep going until it's done\"  → agent calls set_goal\n#     \"what's my goal?\"  → goal_status     ·     \"stop the goal\"  → clear_goal\n#   SLASH COMMAND (if you added the command block):\n#     /goal              → shows \"no active goal\"\n#     /goal set \"say hi once you've written a haiku\"   (no --command: tests the GOAL_COMPLETE path)\n#     /goal pause, /goal resume, /goal clear\n#     /goal set \"\u003cthing\u003e\" --command \"\u003ccmd that exits 0\u003e\"   (tests deterministic completion)\n```\n\nIf `/goal` does nothing, the command-registration/`command.execute.before` path needs adjustment for\nyour OpenCode version — open an issue with your version (`opencode --version`).\n\n---\n\n## Related work \u0026 a high five 🙌\n\nHuge props to **[@mirsella](https://github.com/mirsella)** and\n**[opencode-goal](https://github.com/mirsella/opencode-goal)** — they shipped the original\n\"Codex-style long-running goals for OpenCode,\" and it's a clean, lightweight take that proves the idea.\nIf you want something simpler and model-judgment-based, go give it a star. 🌟\n\n`opencode-autogoal` heads in a different direction: **deterministic `--command` verification**,\n**turn/time limits**, **templates**, and a **conversational tool interface** so you set goals by just\ntalking. Different trade-offs, same good idea. Thanks for blazing the trail. 🤝\n\n---\n\n## License\n\nMIT © VerbalChainsaw\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverbalchainsaw%2Fopencode-autogoal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fverbalchainsaw%2Fopencode-autogoal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverbalchainsaw%2Fopencode-autogoal/lists"}