Connect your first workspace
You need Python 3.10+, Herdr, and an authenticated coding CLI such as Claude Code or Codex.
Run one installer on the machine that owns your workspace.
In the dashboard, create a User + runner key and save it when shown.
Run ania start from the repository you want Ania to use.
1. Install Herdr and Ania
gh api -H "Accept: application/vnd.github.raw+json" \ repos/qywu/ania/contents/install.sh | sh
The repository is currently private, so first authenticate GitHub CLI with gh auth login. The installer uses no sudo, installs Herdr when needed, creates an isolated Ania environment under ~/.local/share/ania, and links the command into ~/.local/bin. Run the same command again to update.
2. Configure local credentials
Add these values to ~/.zshrc.secrets. The Ania API key authenticates the local client to this website. The Anthropic key stays on your machine and powers the default supervisor.
export ANIA_BASE_URL=https://ania.reasoningcats.com export ANIA_API_KEY=ania_... export ANTHROPIC_API_KEY=sk-ant-...
3. Start from a workspace
cd ~/code/my-project ania start improve-search # Or include the initial requirements immediately: ania start improve-search --task "Improve search relevance and verify the tests."
Ania uses the current directory, detects its Git origin when present, registers the machine, creates the task and a unique attempt, starts Herdr, launches Claude Code with Opus 5 and high thinking effort by default, and starts the background synchronization daemon. Codex defaults to GPT-5.6 Sol with high thinking effort. Choose the Solver CLI, model, and effort under Requirements → Agents; a running Solver keeps its current session and the new settings apply on its next launch or restart.
Tasks are work; machines execute it
The durable work request, including its chat, requirements, current status, and history.
Example: improve-searchThe laptop, workstation, VM, or GPU host where Ania has local workspace access.
API name: runnerOne continuous interactive execution. It can work, pause, or sleep until a human explicitly stops it.
API name: runThe dashboard uses the familiar words machine and attempt. The API retains runner and run for protocol compatibility. One machine can execute many tasks over time, while renewable attempt leases prevent two machines from executing the same task concurrently.
Search outcomes from every attempt
The Results page searches structured attempt projections across task names, repository identities, public requirements, status summaries, sanitized Judge findings, and artifact metadata. Filter by repository or verdict, then copy the search URL or open a stable result link for its exact task, attempt, evidence, and timestamps.
Ania's Director can use state(action="search_results") to retrieve the same evidence when an earlier task may contain a useful decision, failure, benchmark, patch, or verification result. Search uses SQLite full-text indexing and returns durable citations rather than raw terminal captures. Hidden Judge rubrics and private tests are never indexed.
Group tasks and reuse guidance by repository
When a workspace is a Git checkout, Ania uses origin when available and otherwise upstream. This keeps the repository that receives pushes and pull requests authoritative, including for fork checkouts. SSH and HTTPS remotes normalize to one stable identity, so tasks on different machines can share the same repository page. Monorepo tasks also retain their relative subdirectory.
Repository rules and skills are versioned on the website. A new attempt receives an immutable snapshot, so editing guidance never changes an attempt that is already running. Ania may propose a learned repository rule or skill, but a signed-in human must approve it on the repository page before it reaches future attempts. The task Status tab lists the origin and revision of effective requirements, repository policy, machine rules, and skills.
Machine rules are configured locally with ania machine-rules --set-file FILE. Their contents never leave the runner; the website receives only whether they are configured and a content revision. Skills use the explicit scopes task, repository, and machine.
Chat is the primary task interface
Each task opens on its Chat tab. Messages support Markdown headings, lists, links, code blocks, tables, and images. Use Attach image to upload a PNG, JPEG, GIF, or WebP image up to 5 MB; the image is stored with the task and inserted into the message as Markdown.
When Ania verifies the requested work, it reports the outcome and puts the Director to sleep. The current attempt and Herdr terminals remain available, while the read-only Monitor continues watching. Any follow-up chat message forces the Director to wake in that same attempt; use Stop only when you want to end the attempt and close its terminals.
After the machine confirms the task is stopped, Delete task becomes available in the task header. It permanently removes the task's attempts, chat, commands, events, attached images, artifact metadata, and terminal-session records from Ania. It never deletes the repository workspace or its files.
Requirements have their own tab. Attempts, commands, events, and low-level identifiers live under History so they remain available for audit and troubleshooting without crowding normal interaction.
An asynchronous Monitor watches; the Director acts
By default, a tool-free Claude Sonnet 5 Monitor runs with low thinking effort and checks changed Herdr terminal output about every 30 seconds. It receives a bounded capture from the Primary Solver and every task-owned Helper window; the independent Judge is excluded. Its provider request runs in a background lane, so it never blocks chat wakeups or the Director. Its current phase, summary, Solver state, model, timestamp, and escalation status appear in the live activity card at the top of Chat.
The Monitor has no tools and cannot type into any terminal. It detects frozen screens, cosmetically changing retry/poll patterns, and repeated summaries with no new concrete outcome. A suspected silent failure wakes the Director, which independently checks process state, durable logs, exit codes, and expected artifacts before intervening. Configure separate frozen-screen, repeated-pattern, semantic-no-progress, and similarity thresholds under Requirements → Agents. Provider credentials remain local, and raw captures are not uploaded.
A live goal graph directs work; a second coding agent judges outcomes
Every task has a durable goal DAG. Parent links organize goals and subgoals into an outline, while dependency links determine which branches are ready and which are blocked. The Plan tab offers both outline and graph views, shows parallel-ready branches, and attaches execution todos, Herdr panes, external jobs, evidence, and Judge state to each goal.
The Director can refine this plan while work runs: it may add required discovered subgoals, change grouping or dependency links, and create or update execution todos. It cannot weaken existing requirements, make a required goal optional, delete a required outcome, introduce a cycle, or mark its own work passed. Every mutation is revision-checked and retained in append-only plan history. Long-running jobs can therefore wait in one branch while other non-conflicting ready branches proceed.
Every task has a Judge; it cannot be disabled. The Director invokes the Judge independently for each required goal, then invokes it once more without a goal for final integration. Completion requires fresh passing verdicts for every required goal and final integration. Completing every todo is useful execution evidence, but never passes a goal by itself.
The Judge runs as a separate Claude Code process by default, with Codex available as an alternative, asynchronously in its own Herdr terminal. It receives only the shared requirements plus the selected goal for a goal evaluation, or the shared requirements plus every goal for final integration. It inspects and tests a disposable snapshot containing the Solver's tracked, dirty, and untracked files; its probes cannot modify the Solver workspace. Open Terminal and switch among Solver, Judge, and Shell when direct inspection is useful.
Under Plan (the successor to Goals & requirements), an owner can manage goal structure, dependencies, public requirements, todos, and goal-specific hidden Judge material. Shared requirements, agent configuration, and final-integration Judge material live under Settings & requirements. The normal task API, command queue, Director, Solver, and Monitor receive only private evaluation revisions and fingerprints. When the Director invokes a Judge, the runner fetches only that invocation's private specification just in time, creates the files only in the disposable snapshot, and removes them after the verdict. Private paths and literal content are redacted from durable results.
The Judge returns a structured pass/fail verdict with checks, failures, limitations, the evaluated commit, and public/private requirement and workspace fingerprints. Editing an acceptance requirement invalidates its verdict plus final integration; a workspace change makes earlier snapshot verdicts stale at completion time. Goal progress and sanitized findings appear above Chat.
One task workspace, multiple visible Herdr windows
Each task reports its Herdr session, task workspace, named windows, nested panes, occupants, and lifecycle states in the Herdr session card. One protected Primary Solver owns implementation and integration. When bounded, non-conflicting help is useful, the Director creates named Helper shell, Claude Code, or Codex windows instead of asking the Primary Solver to use opaque background Task/Monitor jobs. Work needing overlapping ownership, its own branch or PR, or an independent lifecycle belongs in another task.
- Open Open Solver or Open Helper on any reported pane to see its exact live screen and interact with it. Window and pane IDs are shown explicitly for troubleshooting.
- Primary Solver remains the authoritative Claude Code or Codex pane; it cannot be closed through Helper-window controls.
- Helper windows have one scoped purpose and do not compete with the Primary Solver.
- Judge is the independent evaluator in its disposable snapshot, not a Helper.
- Shell creates a separate temporary Bash/Zsh tab rooted in the task workspace and removes it when the web view closes.
- The server receives only sanitized topology and lifecycle metadata. It does not receive terminal text, commands, process arguments, or workspace contents.
- A valid Google browser session is required. Browser and runner derive an ephemeral P-256 shared key and exchange AES-GCM encrypted frames; Ania only relays ciphertext.
- Only one web terminal may be active per runner. Closing it releases the controller without stopping the task or its agents.
The client is the Ania repository
The local client and agent harness are open source at github.com/qywu/ania. The website is monitoring and control; all terminal execution remains in the client.
Commands including init, status, peek, attach, pause, resume, and stop.
ania/cli.pyRunner daemonRegistration, synchronization, command execution, heartbeats, and reconnect behavior.
ania/runner.pyAPI clientThe versioned HTTP and WebSocket client used to communicate with this service.
ania/control_plane.pyDirector runtimeThe local agent loop that reads Monitor handoffs, guides the Solver, and invokes the Judge.
ania/supervisor.pyUseful client commands
| Command | Purpose |
|---|---|
ania start NAME | Create and start a remotely monitored task in the current directory. |
ania start | Register and run the machine daemon; bootstrap a first task only when none exists. |
ania remote-status NAME | Read the server-side desired and observed state. |
ania status NAME | Show detailed local supervisor state. |
ania peek NAME | Read recent worker terminal output without attaching. |
ania attach NAME | Attach to the live Herdr terminal. |
ania say NAME "..." | Ask a question or update requirements from the local CLI. |
ania chat NAME --follow | Follow the human/agent conversation. |
ania skills [NAME] [--task TASK] | Inspect effective machine, repository-snapshot, and task skills with revisions. |
ania promote-skill TASK SKILL | Propose a learned skill for human-approved repository sharing. |
ania machine-rules [--set-file FILE|--clear] | Inspect or replace local administrator-owned machine rules. |
ania pause|resume|stop NAME | Change local supervision state. |
ania runner --once | Force one remote synchronization cycle. |
Choose the narrowest API-key scope
Send an API key in the HTTP Authorization: Bearer … header. Keys are shown once, stored only as hashes, and can be rotated or revoked from the dashboard. Every Google identity has a private Ania workspace; keys created while signed in belong only to that workspace.
| Key type | Use it for | Access within your workspace |
|---|---|---|
| Runner | A dedicated, pre-provisioned runner daemon | Register one runner, heartbeat, receive commands, and upload events |
| API user | Scripts and integrations | Read and control your tasks and view your runners |
| User + runner | The normal ania start workflow | Both task and runner APIs |
| Full access | Trusted workspace administration only | All APIs in your workspace, including creating, rotating, and revoking its keys |
Automate Ania with REST
All application endpoints are versioned under /api/v1. Use JSON request bodies and bearer authentication. See the interactive OpenAPI reference for generated schemas.
List tasks
curl "$ANIA_BASE_URL/api/v1/tasks" \ -H "Authorization: Bearer $ANIA_API_KEY"
Search structured results
curl --get "$ANIA_BASE_URL/api/v1/search" \ -H "Authorization: Bearer $ANIA_API_KEY" \ --data-urlencode "q=Qwen3 parity router replay" \ --data-urlencode "verdict=passed" \ --data-urlencode "limit=10"
Create a task assigned to a registered runner
curl -X POST "$ANIA_BASE_URL/api/v1/tasks" \
-H "Authorization: Bearer $ANIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "improve-search",
"runner_id": "runner_...",
"requirements": "Improve search relevance and run the tests.",
"start": true
}'Send a message or change state
# Valid action types:
# start, pause, resume, stop, send_message, update_requirements, configure_agents
curl -X POST "$ANIA_BASE_URL/api/v1/tasks/$TASK_ID/actions" \
-H "Authorization: Bearer $ANIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"send_message","payload":{"message":"Please run the full test suite."}}'Delete a stopped task
The runner must have reported the task as stopped; a pending Stop request is rejected to avoid orphaning a live worker.
curl -X DELETE "$ANIA_BASE_URL/api/v1/tasks/$TASK_ID" \ -H "Authorization: Bearer $ANIA_API_KEY"
Endpoint summary
| Method and path | Scope | Purpose |
|---|---|---|
GET/health | Public | Service health and version |
GET/runners | User | List registered execution machines |
POST/tasks | User | Create a task and optionally start its first run |
GET/tasks | User | List task projections |
GET/tasks/{task_id} | User | Read desired state, observed state, requirements, and status |
GET/search | User | Full-text search structured results with repository, task, runner, status, verdict, and time filters |
GET/results/{result_id} | User | Read one stable attempt result and its evidence links |
GET/tasks/{task_id}/results | User | List structured results for every attempt of one task |
DELETE/tasks/{task_id} | User | Purge a runner-confirmed stopped task and its retained history; never delete workspace files |
GET/PUT/tasks/{task_id}/evaluation-spec | User | Read or update the private, independently revisioned Judge rubric and test files |
GET/POST/tasks/{task_id}/goals | User | List or create independently judged task goals |
PUT/DELETE/tasks/{task_id}/goals/{goal_id} | User | Revise, regroup, link dependencies, reorder, or remove a goal |
POST/tasks/{task_id}/goals/{goal_id}/todos | User | Create an execution todo linked to a goal |
PUT/DELETE/tasks/{task_id}/goals/{goal_id}/todos/{todo_id} | User | Update ownership, state, evidence, or remove a todo |
GET/tasks/{task_id}/plan-events | User | Read append-only goal and todo mutation history |
GET/PUT/tasks/{task_id}/goals/{goal_id}/evaluation-spec | User | Read or update that goal's hidden Judge rubric and private tests |
GET/tasks/{task_id}/goals/{goal_id}/evaluations | User | Read the goal's durable Judge verdict history |
GET/runners/{runner_id}/tasks/{task_id}/evaluation-context | Bound runner | Fetch the assigned task's private Judge context just before evaluation |
GET/POST/runners/{runner_id}/tasks/{task_id}/plan[-actions] | Bound runner | Read or safely refine the assigned task's goal DAG and todos |
GET/repositories | User | List normalized Git repositories and task/checkout counts |
GET/repositories/{repository_id} | User | Read repository tasks, safe checkout metadata, rules, and skills |
PUT/repositories/{repository_id}/rules | User | Update versioned shared repository rules |
POST/PUT/DELETE/repositories/{repository_id}/skills… | User | Manage versioned repository skills |
POST/runners/{runner_id}/tasks/{task_id}/repository-proposals | Bound runner | Propose a repository rule or skill without publishing it |
POST/repositories/{repository_id}/proposals/{proposal_id}/decision | User | Approve or reject a runner proposal for future attempts |
POST/tasks/{task_id}/actions | User | Start, pause, resume, stop, message, update requirements, or configure task agents |
GET/tasks/{task_id}/runs | User | List attempts for a task |
GET/runs/{run_id} | User | Read one execution attempt |
POST/runs/{run_id}/actions | User | Target an action at a specific active run |
GET/tasks/{task_id}/events | User | Read the durable event timeline; accepts limit |
GET/tasks/{task_id}/commands | User | Read command and acknowledgement history |
GET/tasks/{task_id}/chat | User | Read human/agent messages |
POST/tasks/{task_id}/chat-images | User | Upload a validated task-chat image up to 5 MB |
GET/chat-images/{image_id} | User | Read an authenticated task-chat image |
GET/tasks/{task_id}/artifacts | User | List explicitly uploaded artifact metadata |
GET/POST/DELETE/api-keys… | Admin | List, create, rotate, and revoke API keys |
Runner endpoints are normally client-managed
The Ania daemon prefers an outbound WebSocket at /api/v1/runners/{runner_id}/ws. It sends heartbeats and ordered event batches and receives structured commands. If WebSocket connectivity fails, it falls back to authenticated REST long polling.
| Method and path | Purpose |
|---|---|
POST/runners/register | Register identity, name, version, capabilities, and capacity |
POST/runners/{id}/heartbeat | Report health, capacity, and active leases |
GET/runners/{id}/commands?wait=25 | Long-poll pending commands |
POST/runners/{id}/commands/{command_id} | Acknowledge accepted, rejected, superseded, or completed status |
POST/runners/{id}/events | Commit an ordered event batch |
WS/runners/{id}/ws | Low-latency commands and web-terminal offers |
GET/runners/{id}/terminal-sessions | REST fallback for pending terminal offers |
WS/terminal-sessions/{id}/runner | Relay encrypted Herdr terminal frames |
Runner keys bind to the first runner ID they register. Delivery is at least once: commands and events carry stable IDs, and both sides deduplicate them.
Execution and secrets stay local
- The server stores users, task definitions, normalized repository metadata, repository rules and skills, desired state, commands, events, chat, explicitly attached chat images, status projections, runner heartbeats, API-key metadata, and web-terminal audit metadata in SQLite.
- Deleting a stopped task removes its server-side content and history. A content-free task ID, runner ID, and deletion timestamp remain as a protocol tombstone so a runner can safely retry a final event whose acknowledgement was lost.
- The runner owns Herdr processes, terminal state, local verification, provider credentials, and its durable outbox.
- The workspace owns source files, build outputs, shell tools, and secrets. The server cannot browse the repository; an authenticated web shell is created only inside the selected task workspace and its contents remain end-to-end encrypted.
- Raw terminal captures and workspace files are not uploaded by default. Opt-in web-terminal contents are encrypted between browser and runner and are not persisted. Chat images require an explicit upload from the authenticated user; other artifacts require an explicit upload policy.
- Set ANIA_ALLOWED_WORKSPACE_ROOTS to a comma-separated allowlist to restrict directories a runner may use.
Common checks
| Symptom | Check |
|---|---|
| HTTP 401 | The key is missing, invalid, rotated, or revoked. Open a fresh shell after editing your secrets file. |
| HTTP 403 | The key lacks the required scope or a runner key is bound to a different runner ID. |
| Runner is offline | Run ania runner --once, then inspect local logs and network access to this HTTPS origin. |
| ania start cannot create a task | Use a User + runner key; a Runner-only key cannot call the task API. |
| Supervisor model error | Confirm ANTHROPIC_API_KEY is available in a fresh shell. Coding CLI authentication is separate. |
| Workspace rejected | Ensure the current directory is inside one of ANIA_ALLOWED_WORKSPACE_ROOTS. |