Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
},
"metadata": {
"description": "Shared coding-agent tooling for BoxLite repositories",
"version": "0.1.5"
"version": "0.1.6"
},
"plugins": [
{
"name": "boxlite-agent-tooling",
"description": "Shared BoxLite coding-agent skills, auditors, hooks, and repository tooling.",
"version": "0.1.5",
"version": "0.1.6",
"source": "./plugins/boxlite-agent-tooling"
}
]
Expand Down
4 changes: 2 additions & 2 deletions .github/plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
},
"metadata": {
"description": "Shared coding-agent tooling for BoxLite repositories",
"version": "0.1.5"
"version": "0.1.6"
},
"plugins": [
{
"name": "boxlite-agent-tooling",
"description": "Shared BoxLite coding-agent skills, auditors, hooks, and repository tooling.",
"version": "0.1.5",
"version": "0.1.6",
"source": "./plugins/boxlite-agent-tooling"
}
]
Expand Down
14 changes: 11 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Agent Tooling Development

- Keep reusable implementation in `plugins/boxlite-agent-tooling/`.
- When changing non-trivial Bash hooks, gates, or libraries, load
`plugins/boxlite-agent-tooling/.agents/skills/shell-engineering/SKILL.md` and
preserve the executable's host-facing stdin/stdout/stderr/exit contract.
- Keep consumer manifests declarative and free of secrets.
- Preserve fail-closed validation: invalid profiles and missing dependencies
must write a clear error to stderr and exit nonzero.
Expand All @@ -21,6 +24,9 @@
- Host-specific assets reach the generic layout through symlinks: `skills` ->
`.agents/skills` and `agents` -> `.claude/agents`. Add a host by pointing a manifest
at those names, not by copying the trees.
- Hook manifests are normalized twins, not one parser-agnostic file: Claude discovers
`hooks/hooks.json` with `asyncRewake`; Codex and the generic manifest declare
`hooks/codex-hooks.json` with `async`. No other behavioral drift is allowed.
- `guidance/workflow.md` is the canonical engineering workflow every consumer's
AGENTS.md/CLAUDE.md carries in a marker-fenced block (`scripts/sync-guidance.sh`
splices on explicit install; the commit/push gates verify with `--check` —
Expand All @@ -30,10 +36,11 @@
the begin marker's content hash is what tells tampering from staleness.
- `plugins/boxlite-agent-tooling/host-parity.test.sh` pins the cross-host contract:
same identity in every manifest, marketplaces advertising the shipped version, one
skills tree, one agent-spec set, one hooks file inside the schema both hosts parse.
Run it after touching any manifest, marketplace, symlink, or hooks.json.
skills tree, one agent-spec set, and normalized hook manifests whose only allowed
difference is the host-specific background-delivery key. Run it after touching any
manifest, marketplace, symlink, or hooks JSON.

<!-- agent-tooling:guidance:begin rev=3de47b436b45 sha256=8afd17bc8f27 -->
<!-- agent-tooling:guidance:begin rev=7d86a1478761-dirty sha256=29f917c92f67 -->

> Managed by **boxlite-ai/agent-tooling** — do not edit between the markers. Change `plugins/boxlite-agent-tooling/guidance/workflow.md` there, then rerun `./.agent-tooling/install.sh` here.

Expand Down Expand Up @@ -106,6 +113,7 @@ Every change goes: understand → research → design → implement → test →

- Verify external findings against the working tree before acting. Reviews, lint, and PR comments work from a snapshot — they may name deleted code. `git grep` and `git diff` first.
- Audit verdicts through the Stop gate: when a turn asserts something as established — a fix that works, tests that pass, a root cause, an ops/infra finding, "no issues", a factual answer — let the gate triage the final turn. If it blocks, invoke the `verdict-auditor` subagent synchronously (Task, run_in_background: false) using the exact transcript, session-scoped dossier paths, and audit generation in the block instruction; the auditor (never you) writes the dossier. Retain its handle while waiting: if a real user message is steered in before it returns, cancel/interrupt the auditor, revoke that audit generation, discard its dossier, and handle the new message; re-audit only if the revised turn still needs a verdict. The Stop gate triages the WHOLE final turn (every assistant text since the last real user message) straight from the transcript — triage is a three-tier cascade, cheapest first: text the _harness_ wrote into the assistant slot (API errors, quota notices) asserts nothing and is allowed with no model call; a small set of assertion-only forms ("173/173 tests pass", a line-initial "Verified …", a whole-line "done.") blocks with no model call; everything else goes to a fast model judging "is this a conclusion the reader must take on trust, with nothing shown that produced it?" — so a turn that quotes the output, counts or file:line behind its claims ends freely, while one that just asserts the result does not — falling back to a curated pattern list (EN+中文) when no model is reachable — and it blocks until a fresh dossier exists. Prose-ambiguous phrasings ("tests pass", "root cause is", "deploy is healthy") stay with the model on purpose, so a turn merely _discussing_ verdict wording is still allowed. Every allow announces its decision to the human via systemMessage (invisible to the model); a FAIL keeps blocking until its findings are addressed (that loop is deliberate), and a still-fresh FAIL is parked to the matching session-scoped previous-dossier path when your fix moves the tree so the next audit re-checks those findings instead of starting cold; stale/mismatched dossiers are discarded and aged-out ones dropped outright, never blocked on; while `run-verdict-audit.sh` is actually running the gate allows under an `inflight-allow` rung rather than re-blocking you once every few seconds for the whole length of the audit it just demanded — that audit's verdict gates your NEXT turn instead; chat and question turns end freely; when your turn's text has not reached the transcript yet the gate waits briefly, and if it still cannot read it the turn ends UNJUDGED under a `blind-allow` rung; a judged message is never judged twice (flush-race guard). Triage can misread — declaring remains your duty, not only the hook's.
- An auditor still running after 30 seconds opens one interactive choice on hosts that support asynchronous re-wake: Keep waiting, or Force pass because the auditor is taking too long. No response leaves the auditor running. The host cannot dismiss an outstanding question when PASS/FAIL arrives, so a stale card may remain; its generation-bound selection is rejected after terminal completion or replacement. Other hosts publish a non-blocking typed status instead. The first non-empty line `force-pass-auditors: <required reason>` remains the headless/accessibility fallback. An override is recorded as `OVERRIDDEN BY USER`, never PASS, expires within one hour, and is revoked by the next real prompt. It bypasses only `commit-push-auditor` and `verdict-auditor`; installation/guidance checks, PR-review acknowledgement, chained hooks, push ref binding/watchers, permissions, and remote protections still run.
- Honor scope reduction: "drop X" means drop X. Don't bundle adjacent improvements unprompted.
- Treat every failure as a class, not an instance: when one surfaces, find and fix every sibling of the same shape in the same pass — grounded in what's actually there, not speculation. A single-site fix to a systemic bug isn't done.

Expand Down
51 changes: 48 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,51 @@ the already-running parent process. `/reload-plugins` is therefore the final one
step; later valid starts are silent. Repository trust remains a human decision and is
not pre-approved by these files.

### Long-running auditor escalation

`commit-push-auditor` and `verdict-auditor` run normally for their first 30 seconds.
After that, Claude Code's asynchronous `SubagentStart` hook uses `asyncRewake` to wake
the parent with an instruction to open one `AskUserQuestion` card:

- **Keep waiting (Recommended)** — dismiss this escalation and leave the auditor active.
- **Force pass — auditor is taking too long** — override both auditor gates for this
prompt with that user-selected reason.

The card blocks the parent conversation but not the auditor. If the user does nothing,
the audit keeps running. Claude Code exposes no completion hook that can dismiss an
already-rendered question, so the card may remain stale after the audit finishes; a
later click is still safe because the selection command rejects a terminal or replaced
generation. `SubagentStop` closes the exact session, prompt epoch, auditor, and
generation record when completion arrives.
Claude's host-generated `<task-notification>` wake and completion envelopes do not
advance the human prompt epoch. The wake consumes a random generation-bound marker;
prompt closure or same-auditor replacement retains a non-authorizing pending-stop
receipt for each displaced active generation, and every `SubagentStop` adds one
matching completion-delivery credit. Each host completion consumes one credit,
including repeated notifications from a resumed task. This avoids relying on the
transcript, which Claude appends only after
`UserPromptSubmit` hooks finish.

Codex's strict hook schema accepts `async` but not `asyncRewake`, so the generic and
Codex manifests use `hooks/codex-hooks.json`; Claude conventionally discovers
`hooks/hooks.json`. `host-parity.test.sh` normalizes the one delivery-key difference and
requires every command and all remaining behavior to match. Codex receives the same
non-blocking typed status instruction at its next safe conversation point.

For headless or accessibility use, submit this as the first non-empty prompt line:

```text
force-pass-auditors: <required reason>
```

The override is bound to the canonical repository, host session, and new prompt epoch,
expires within one hour, and is revoked by the next real prompt. Runtime state stores a
nonce hash and reason hash, not the bearer or reason. Gate-use logs say `OVERRIDDEN` and
bind commit, push, and Stop uses to their actual diff/subject/tree context. No PASS
dossier is created or rewritten. Installation and guidance checks, PR-review
acknowledgement, chained framework hooks, exact push-ref calculation, PR watching,
host permissions, and remote protections remain in force.

## Shared engineering guidance

`plugins/boxlite-agent-tooling/guidance/workflow.md` is the canonical, domain-neutral
Expand Down Expand Up @@ -283,9 +328,9 @@ bash templates/claude-plugin-bootstrap.test.sh

The parity suite is the cross-host check the two host validators cannot make: it
asserts Claude Code's conventional discovery, Codex's declared paths, and the generic
manifest all resolve to the same skills, agent specs, and hooks file, that every wired
command resolves its root on both hosts, and that the marketplaces advertise the
version the manifests actually carry.
manifest all resolve to the same skills and agent specs, that the host hook manifests
normalize to the same behavior, that every wired command resolves its root on both
hosts, and that the marketplaces advertise the version the manifests actually carry.

After installation, configure repository Git hooks explicitly:

Expand Down
Loading