{"id":49832081,"url":"https://github.com/bermudi/nelsonctl","last_synced_at":"2026-05-13T21:04:35.268Z","repository":{"id":349859652,"uuid":"1203402772","full_name":"bermudi/nelsonctl","owner":"bermudi","description":"little harness for litespec","archived":false,"fork":false,"pushed_at":"2026-04-07T20:49:50.000Z","size":213,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-07T22:30:22.533Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bermudi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-07T02:27:34.000Z","updated_at":"2026-04-07T20:49:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bermudi/nelsonctl","commit_stats":null,"previous_names":["bermudi/nelsonctl"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/bermudi/nelsonctl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bermudi%2Fnelsonctl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bermudi%2Fnelsonctl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bermudi%2Fnelsonctl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bermudi%2Fnelsonctl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bermudi","download_url":"https://codeload.github.com/bermudi/nelsonctl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bermudi%2Fnelsonctl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32999522,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"ssl_error","status_checked_at":"2026-05-13T13:14:51.610Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-05-13T21:04:27.843Z","updated_at":"2026-05-13T21:04:35.263Z","avatar_url":"https://github.com/bermudi.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nelsonctl\n\n`nelsonctl` automates the litespec apply -\u003e review -\u003e fix loop for a single change directory.\n\n## Usage\n\n```bash\nnelsonctl specs/changes/initial-scaffold\n```\n\n## Pi-first setup\n\n`nelsonctl` defaults to Nelson mode when `pi` is installed and no explicit CLI agent override is provided.\n\n1. Install `pi` and confirm `pi --mode rpc --no-extensions --version` works.\n2. Run `nelsonctl init` to create `~/.config/nelsonctl/config.yaml`.\n3. Export the controller credential for your configured provider.\n\nMinimal setup writes a Pi-first config with:\n\n- `agent: pi`\n- OpenRouter controller configuration with a ready-to-use reasoning model\n- Step-specific apply/review/fix models and timeouts\n- `review.fail_on`\n\n## Configuration overview\n\nThere are two separate AI configurations in `~/.config/nelsonctl/config.yaml`:\n\n- `agent` + `steps.*` configure the **coding agent** that edits code.\n- `controller.*` configures the **controller** that drives the apply/review/fix loop.\n\nSupported controller providers are `deepseek`, `openrouter`, `opencode`, `poe`, and `poe-responses`.\n\n```yaml\nagent: pi\nsteps:\n  apply:\n    model: minimax/minimax-m2.7\n    timeout: 30m\n  review:\n    model: moonshotai/kimi-k2.5\n    timeout: 15m\n  fix:\n    model: minimax/minimax-m2.7\n    timeout: 30m\ncontroller:\n  provider: openrouter\n  model: deepseek/deepseek-reasoner\n  max_tool_calls: 50\n  timeout: 45m\nreview:\n  fail_on: critical\n```\n\nCredentials stay in environment variables and are never written into `config.yaml`.\n\n## Controller credentials\n\n- `DEEPSEEK_API_KEY` for `controller.provider: deepseek`\n- `OPENROUTER_API_KEY` for `controller.provider: openrouter`\n- `OPENROUTER_API_KEY` for `controller.provider: opencode`\n- `POE_API_KEY` or `POE_OAUTH_TOKEN` for `controller.provider: poe` and `controller.provider: poe-responses`\n\n### Poe controller provider\n\nTwo Poe protocols are available:\n\n| Provider | API | Endpoint | Auth header |\n| --- | --- | --- | --- |\n| `poe` | Chat Completions (OpenAI-compatible) | `https://api.poe.com/v1/chat/completions` | `Authorization: Bearer ...` |\n| `poe-responses` | Responses (Poe native, recommended) | `https://api.poe.com/bot/{model}` | `Poe-API-Key: ...` |\n\n#### Chat Completions (`poe`)\n\nOpenAI-compatible, best for drop-in use with models that support it:\n\n```yaml\ncontroller:\n  provider: poe\n  model: claude-3-5-sonnet\n  max_tool_calls: 50\n  timeout: 45m\n```\n\n#### Responses API (`poe-responses`, recommended)\n\nPoe's native API. Sends `system_instruction`, `query`/`messages`, `tools`, `tool_calls`, and `tool_results` directly. The model name is embedded in the endpoint URL. Supports tool calling and multi-turn conversations:\n\n```yaml\ncontroller:\n  provider: poe-responses\n  model: claude-3-5-sonnet\n  max_tool_calls: 50\n  timeout: 45m\n```\n\n#### Authentication (both protocols)\n\n- API key: export `POE_API_KEY=poe-...`\n- OAuth: exchange a Poe PKCE auth code for an access token, then export it as `POE_OAUTH_TOKEN`\n- `POE_OAUTH_ACCESS_TOKEN` is also accepted as a fallback alias\n\n## Coding agent configuration\n\n`steps.apply.model`, `steps.review.model`, and `steps.fix.model` are passed directly to the selected coding agent, so the expected format depends on `agent`:\n\n| Agent | nelsonctl field | CLI flag | Expected value format |\n| --- | --- | --- | --- |\n| `pi` | `steps.*.model` | `--model` | `provider/id` or pattern, optionally `:thinking` |\n| `opencode` | `steps.*.model` | `--model` | `provider/model` |\n| `claude` | `steps.*.model` | `--model` | model alias or full model name |\n| `codex` | `steps.*.model` | `--model` | model id accepted by `codex exec --model` |\n| `amp` | `steps.*.model` | `--mode` | one of `deep`, `large`, `rush`, `smart` |\n\nThese formats were checked against each agent's current `--help` output.\n\n### Agent-specific notes\n\n- `pi`: `pi --help` documents `--model` as `provider/id` or a fuzzy pattern, with optional `:thinking` suffix.\n- `opencode`: `opencode run --help` documents `--model` as `provider/model`.\n- `claude`: `claude --help` documents `--model` as an alias like `sonnet` or a full model name like `claude-sonnet-4-6`.\n- `amp`: `amp --help` uses `-m, --mode`, not `--model`. Nelsonctl maps `steps.*.model` to Amp's mode flag.\n\nIf you use `opencode` with Poe as the provider, authenticate opencode itself first, typically with `opencode providers login --provider poe`, and select the OAuth method in the prompt.\n\n## Flags\n\n- `--agent opencode|claude|codex|amp` — explicitly use a CLI agent instead of Pi\n- `--dry-run` — print the execution plan without running anything\n- `--no-pr` — skip PR creation after the pipeline completes\n- `--verbose` — stream full agent output directly to the terminal instead of the TUI\n\n## Examples\n\nDry run remaining phases:\n\n```bash\nnelsonctl --dry-run specs/changes/initial-scaffold\n```\n\nUse a CLI fallback agent and skip PR creation:\n\n```bash\nnelsonctl --agent claude --no-pr specs/changes/initial-scaffold\n```\n\nInitialize config interactively:\n\n```bash\nnelsonctl init\n```\n\n## What it does\n\n1. Reuses or creates `change/\u003cchange-name\u003e`\n2. Resumes from the first unchecked phase in `tasks.md`\n3. Runs each remaining phase through the controller-driven apply/review/fix loop\n4. Runs a fresh final pre-archive review\n5. Pushes the branch and opens a PR unless `--no-pr` is set\n\n## CLI fallback\n\nCLI agents remain supported when you explicitly select one with `--agent` or config. In that case `nelsonctl` runs in Ralph mode and still uses the controller loop, but agent execution happens via shell-out instead of Pi RPC sessions.\n\n## Testing\n\n### Unit and integration tests\n\n```bash\ngo test ./...\n```\n\n### E2E tests with real git (fast, no API keys)\n\nThe `TestE2ERealGit*` tests in `internal/pipeline/e2e_test.go` run the full pipeline state machine against a real git repo in a temp directory with stub agent/controller. They verify branch creation, commit messages, file mutations, and report fields — no network, no API keys, runs in ~0.2s.\n\n```bash\ngo test ./internal/pipeline/ -run TestE2E -count=1 -v\n```\n\nCovers single-phase and multi-phase scenarios with real `git init`, `git commit`, and `git push` (to a local bare remote).\n\n### Live E2E with real agent/controller\n\n`e2e.sh` drives the full pipeline against `~/build/nelsonctl-test/` with the real configured agent and controller. Costs API calls but tests everything end-to-end.\n\n```bash\nbash e2e.sh              # reset test repo + build + run + check\nbash e2e.sh --keep       # skip repo reset (re-run after a code fix)\nbash e2e.sh --debug      # with NELSONCTL_DEBUG=1\nbash e2e.sh --change foo # different change dir\n```\n\nResults are machine-readable: exit 0 = pass, exit 1 = fail. Logs are written to `e2e-logs/` with a `latest` symlink:\n\n```bash\necho $?              # check result\ncat e2e-logs/latest  # read the full output\n```\n\n## Notes\n\n- Run `nelsonctl` from the repository root.\n- The change path should point at a litespec change directory such as `specs/changes/add-dark-mode`.\n- Dry-run prints the resolved mode, agent, step model/mode values, resume state, and remaining phase tasks without creating a lock or branch.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbermudi%2Fnelsonctl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbermudi%2Fnelsonctl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbermudi%2Fnelsonctl/lists"}