jobs · diff
git:20260904.0fc989b to git:20260907.d1d43b8
44 added, 31 removed. Audit A to A.
---
name: jobs
description: Manage agy staffer background jobs - collect results, check status, cancel, follow-up conversation, and setup. Use when an agy job needs collecting, when the user asks "is the agy job done", "show agy's result", "cancel the agy job", "continue the agy conversation", or "set up agy". This is the orchestrator's skill; the persona skills (staffer/researcher/reviewer/implementer) point here.
user-invocable: false
allowed-tools: Bash(node:*), AskUserQuestion
---
# agy jobs
- Job management for the agy-staff plugin. All state is per-repository under `.agy-staff/` (created and git-ignored automatically on first use).
-
- staffer, research, review, and implement always start a background job and return a job id immediately; only ask runs in the foreground. Background jobs never call back: the deliverable is agy's output, not the job id, and collecting it is your job, not the user's.
-
- ## Locating the companion
+ Manage background staffer/research/review/implement jobs. State is per repository in `.agy-staff/`. Only ask runs synchronously.
- This skill file lives at `<plugin-root>/skills/jobs/SKILL.md`; resolve the companion path relative to this skill directory:
+ This file lives at `<plugin-root>/skills/jobs/SKILL.md`:
```bash
- node "<skill-dir>/../../companion/agy-companion.mjs" <subcommand> [args]
+ node "<skill-dir>/../../companion/agy-companion.mjs" <command> [args]
```
- ## Collecting results
+ ## Collect the result
- The job-start output prints the exact collect command — `wait <id> --timeout <n>m`, sized to outlive the job. That one call blocks until the job reaches a terminal state, prints the result, and exits with a machine-readable code. Never parse output to decide whether a job is done; branch on the exit code.
+ 1. Keep the returned job id. Start `wait <id> --timeout 10m` in the background, using the same unsandboxed context as launch. Use a separate wait for each job; never wait for several jobs serially in one shell.
+ 2. For **wait**, branch on the exit code:
- - **One job → one background wait.** Run the printed `wait` through your harness's background command facility (Claude Code's background Bash, a Codex `unified_exec` session), started as soon as the job starts, and pick it up when it exits. While it runs, heartbeat lines on stderr (`still waiting on <id>…`) show liveness.
- - **N jobs → N background waits, never one shell.** Do not wait for several ids serially in a single shell (`wait a; wait b`, a for-loop): it hides each job's completion behind the slowest predecessor and gives you nothing to react to. Start every job's own background `wait` the moment that job starts.
- - **Foreground fallback** (nothing else to do, single job): run `wait <id>` with its 100s default timeout and rerun it while it exits 2.
- - **Match the permission context.** Run `wait`, `status`, `result`, and `cancel` in the same unsandboxed permission context as the corresponding job start. If collected from a different sandbox or permission context, the collector may not see the worker process and can falsely report a running job as crashed.
+ | Code | Meaning | Next action |
+ | --- | --- | --- |
+ | 0 | Finished; result printed | Deliver it. Mention any warnings in the log. |
+ | 2 | Still running; current progress printed | Read the progress, then wait again if work should continue. |
+ | 3 | Error or crash | Read the error and recovery information below. |
+ | 4 | Canceled | Report cancellation. |
+ | 1 | Invalid command or other command error | Quote the error and correct the named problem. |
- Exit codes (`wait`, and `status <id>`): **0** = done — the result is already printed; **2** = still running when the wait's own timeout expired — run the same `wait <id>` again; **3** = error/crashed; **4** = canceled; **1** = generic companion error (e.g. unknown id).
+ For a user progress question or a mid-run update, call `observe <id>` before reporting progress, even if a wait is already running. Report changed tool activity, response text or an actionable warning; do not repeat an unchanged snapshot. Do not call observe again just to duplicate the snapshot returned by a soft-expired wait.
- Delivering an exit-0 result: a short report (about a screenful) → verbatim; a long report → the verdict/key points plus the result-file path (printed at job start), expanding sections on request. A `done_with_warnings` run (agy reported an error after producing a complete response) still exits 0 — the warning is on stderr / in the job log; mention it, deliver the response. If it was an implement job whose output says the working tree changed, also show `git diff`; if the task explicitly asked agy to commit or open a PR, report and verify agy's result instead of doing Git delivery yourself.
+ Keep the pending wait open while observing. Host command collectors (for example, Codex `write_stdin`) only collect that command's output; they do not call observe or read AGY progress for you. Prefer background completion delivery; when polling is required, use a substantial supported wait (typically 30–60s), not repeated 1s empty polls. An outer `functions.wait` resumes a yielded `functions.exec` call, not an AGY job. During silent waiting the session has no output; only completion or soft expiry produces the result/snapshot for its collector. Observe reads job state independently, not wait’s output.
- ## Subcommands
+ A wait expires without stopping the worker. Cancel only when the task calls for stopping; a quiet period alone is not a reason. If progress leaves a specific question unanswered, read only the relevant part of the file named in `details`, such as the last 4 KiB of its diagnostic log. Do not load an entire stream by default.
- - **wait `[job-id] [--timeout <dur>]`** — block until the job (default: the most recent one) reaches a terminal state, then print its result. Its own `--timeout` (default 100s, no upper limit) is independent of the job's; expiring is not a failure (exit 2 = run it again).
- - **status `[job-id]`** — list jobs (render as a compact table) or show one job with a log tail; with an id it exits with the same codes as `wait`.
- - **result `[job-id]`** — re-print the stored output of a finished job (default: the most recent finished one). Deliver per "Collecting results".
- - **cancel `<job-id>`** — kill a running job and mark it canceled.
- - **continue `--prompt "follow-up text"`** — send a follow-up to the most recent agy conversation in this repo (any mode; quota-friendly — agy serves prior context from cache). `--conversation <id>` targets an older one; ids are tracked in `.agy-staff/state.json` and shown on the `[agy-staff]` stderr line. Execution style follows the resumed mode: a continued ask is foreground, everything else returns a job id.
- - **setup `[--apply] [--restrict <modes|none>]`** — optional hardening for restricted runs. Read `references/setup.md` before running it.
+ Deliver short results verbatim; summarize long results with their file path. Keep quoted verdicts, numbers and errors exact. For implement, also report the workspace state and inspect changes with `git diff`; verify any Git delivery that the user explicitly requested.
- ## Rules
+ Follow through to a result unless the user asked only to launch. If the host cannot deliver background command results, use shorter waits (bare `wait` defaults to 100s). The host controls when the model receives a tool result; this plugin cannot schedule a future model invocation by itself.
- - Never paraphrase verdicts, numbers, or error text — quote them. Summarizing a long report is fine, but what you do quote must be verbatim.
- - Report just the job id and stop only when the user explicitly said not to wait.
- - If a `--restricted` run keeps returning empty responses even after setup, suggest dropping `--restricted` (the default) for that command.
+ ## Other commands
- ## Failure protocol
+ | Command | Purpose |
+ | --- | --- |
+ | `observe [id]` | Always return bounded JSON: progress while running, terminal metadata and result/recovery pointers when finished. Never return report text. |
+ | `status [id]` | List jobs or show one job's state and log tail. |
+ | `result [id]` | Reprint stored output; default to the latest finished job. |
+ | `cancel <id>` | Stop that job's execution. Interrupting wait does not cancel it. |
+ | `continue --job <id> --prompt "..."` | Resume the job's conversation with its original mode/model/profile; create a linked new job. |
+ | `continue --prompt "..."` | Continue the latest conversation; `--conversation <id>` selects a known older one. |
+ | `restart <id>` | Start the original task/configuration again without its conversation; create a linked new job. |
+ | `setup [--apply] [--restrict <modes\|none>]` | Optional permission setup; read `references/setup.md` first. |
- - If the companion exits with an error, quote its error message verbatim, add one line of your own diagnosis and the suggested next step, then stop — do not retry with different flags unless the error itself names one.
- - `operation not permitted` on `~/.gemini/...` or `bind: operation not permitted` means the companion ran inside a command sandbox, where agy cannot work. See `references/troubleshooting.md`; rerun unsandboxed instead of retrying as-is.
- - If `wait`/`status`/`result` reports a job as crashed with no stored result, check whether the management command ran in a different permission or sandbox context from the job start. Rerun from the same unsandboxed context before treating the job as crashed.
- - Never change directories, search the filesystem, or pick a different repo to satisfy a precondition — preconditions are safety features, not obstacles.
+ Wait/observe default to the latest job. Observe uses the same status exit codes, but exit 0 means **finished, not full result delivered**. Collect the existing wait session, or use `result <id>` if none is pending; do not start another wait or expect observe to consume the pending session. Failed/canceled observations provide bounded recovery metadata; wait/result deliver the full report. A continued ask remains synchronous.
+
+ Continuation and restart may be invoked from the root or any subdirectory of the same worktree; execution returns to the original cwd. Generic `continue` fails for an unrecorded conversation ID. It does not search other worktrees or infer configuration from an unrelated conversation. For continuation, explicit model/profile flags override the inherited values.
+
+ Cancel records a request first and returns success only after the worker has stored the cancellation report and published `canceled`. A crashed job keeps its crash diagnostics. A cancellation error requires inspection; it does not mean execution has stopped.
+
+ ## Progress and recovery
+
+ Progress contains up to five recent tool calls, input/output excerpts, and the latest response text. Timestamps, incomplete text and truncation are labeled. It is a snapshot, not a judgment of useful progress. Reads do not consume history or reset deadlines. Payload limits and file layout are in `../../docs/REFERENCE.md`.
+
+ The worker has a separate hard limit: default 60m, configurable with launch `--timeout` up to 120m. AGY receives the same response timeout; the worker independently enforces the overall budget, including initialization. At that limit it stops execution. If a complete response has already arrived, it delivers that response with a warning; otherwise it reports `hard_timeout`, the last snapshot, logs, known conversation ID and original configuration. Before recovery, inspect `git status` and `git diff` so partial changes are accounted for. Prefer `continue --job` when a conversation exists; otherwise use `restart`. Each creates a fresh 60m budget unless `--timeout` is specified, and preserves the old terminal record. Restart refreshes workspace context; older specifications explicitly label historical snapshots and append current context. Recover only within the user's authorization; never restart automatically because a wait expired.
+
+ Warning-free success removes intermediate stream/snapshot files after results are stored. Errors, cancellation, hard timeout and warning results retain them; results, logs and conversation metadata remain available. Older jobs may have no progress files.
+
+ Quote errors and add a concise diagnosis. For sandbox/permission errors or an apparent crash without a result, check that collection uses the same unsandboxed context as launch; see `references/troubleshooting.md`. For restricted empty responses, relay the companion's permission guidance. Do not switch repositories to bypass a precondition.