AIWG 2026.9.9 — Say what is actually there

AIWG 2026.9.9 — Say what is actually there

Release date: 2026-09-13

Channel: stable

Supersedes v2026.9.8, which was tagged but never published — its npm publish failed on

a test that the release itself exposed, and the fix landed after the tag.

This release is about AIWG describing its own state accurately. Several commands reported a declaration where they should have reported reality — which version is running, what a migration will move, what a deploy left behind — and the gap was invisible precisely because every check looked green. If you have run AIWG in the same project across several versions, the pruning and context-budget work here is worth taking.

`version` reports the binary that ran

`aiwg version` read the canonical install rather than the executing one. On a host where an npm global shadowed a source checkout it confidently reported the source version and path — the first command anyone runs to answer "what am I on" was describing the install that was not running, while `installation show` correctly reported `State: mismatch` at the same moment.

`path:` is now always the executing root, and when the canonical install declares a different root the notice names it, its version, and points at `aiwg installation show`.

Drift has a stated remedy

`installation switch` and `adopt` write `installation.json` and nothing else. On a host where an npm global shadows a declared source checkout, `switch` is a no-op — the declaration is already what it would write — and `adopt` "resolves" the mismatch by capitulating to the copy the operator is trying to stop using. The command that actually fixes it, `npm link`, appeared nowhere in AIWG's output.

`installation show` now prints a Resolve block tailored to the direction of the drift, and says plainly that these commands are declaration-only. `adopt` refuses to abandon a declared install without `--yes`, showing both sides first.

Long-lived projects stop accumulating

Rules were never in scope for the target-provider prune, so a project deployed continuously since earlier versions kept every rule any past version ever wrote: 219 agents and 68 rules where a fresh deploy today writes none, putting the project 9% over its own startup-context budget with `.claude/rules/*.md` alone consuming ~117K of a 200K window. The budget warning described the symptom without naming the cause.

Refresh now prunes orphaned rules — gated on the managed marker, so operator-authored rules and project-local bundles are untouched — and `refresh --dry-run` lists what it would remove instead of printing only "Checking for stale deployments...". The context warnings name the cause and point at the dry run.

Session start stops costing context

The SessionStart hook invoked its script with no arguments, and with no arguments the script printed its usage block and exited 0 — so a help message for a command the agent never calls became the first content of every session transcript. It was also registered twice, because registration matched only on AIWG's own id and appended a managed entry beside an identical untagged one.

No-argument invocation is now silent, help moved behind `help`/`--help`, and registration adopts an untagged entry instead of duplicating it.

Migrations say what they are about to narrow

`workspace-context migrate` classifies a source by filename, which is right when the content is provider-specific and quietly wrong when a project used `CLAUDE.md` as its main context file — the normal path, since `CLAUDE.md` was the conventional home for project context long before `WORKSPACE.md` existed. Project-neutral methodology got narrowed to one provider with nothing erroring.

`migrate --dry-run` now reports, per source, how much operator content moves and to which scope, and flags a provider-named source carrying enough content to be a decision rather than a default.

Repositories can declare what they hold

A privacy-classification vocabulary already existed per artifact but never reached project scope, so the difference between a repo routinely excerpted for partners and one holding executed agreements was carried only by prose and a free-text note. `project` now accepts `classification`, `pii`, and handling flags, and `doctor` warns when a repo declared private has a secondary remote that pushes on release.

The access manifest gained the write path it was missing: `aiwg repo-access add`, `remove`, and `audit`, the last reporting git subdirectories that are formally denied because nobody registered them.

Rules answer the question you ask

Discovery ranking weights trigger phrases heavily, and rules have always supported them — 2 of 168 declared any. A skill usually has a distinctive name you might guess; a rule's name describes the policy, not the question. Nobody queries "delivery-policy", they query "should I open a pull request". So the artifacts that encode "you may not do this without authorization" were the ones least able to surface.

The 16 rules an agent most needs mid-task now declare triggers written as the question being asked:

"do I need permission for this"  -> human-authorization
"where do I put an api key"      -> token-security
"can I commit to main"           -> delivery-policy
"should I delete this test"      -> anti-laziness
"is this command destructive"    -> ops-safety

No indexer change was required. `docs/development/rule-creation-guide.md` documents the mechanism — there was a creation guide for every artifact type except rules — and `npm run lint:rule-triggers` reports coverage so the remaining rules close incrementally.

The phrases stay out of your context: deployed rules keep their frontmatter, so triggers are stripped at deploy. They exist for the index, not for the agent reading the rule.

The bibliography resolver extracts what it counts

The resolver shipped in the previous cycle counted correctly and extracted almost nothing. Against real e-prints it returned no title on 52 of 66 entries of an ACL paper, none on a biblatex one, and "ArXiv preprint" as a title three times — so `Confirmed by` could not be populated at all. Five parse gaps, each from a real shape it met: `\href {url} {Title}` with spaces, biblatex `\field`, bare `abs/NNNN` arXiv ids, style-dependent year placement, and brace-delimited `.bib` fields, which had never parsed and which the report did not name.

Unresolved entries now say so. A printed title that matches two corpus REFs — the corpus inducts some works twice — is resolved deterministically with the twins listed in `ambiguous`, instead of silently depending on file order. Measured against hand-resolved citation sidecars on four dialect cases: 57 of 60 edges, the remainder corpus-side duplicates.

Also in this release

  • `--help` reaches real usage for `installation`, `repo-access`, and `steward permissions`.
  • `main-only-blocked` is accepted as a deprecated force-push alias, naming the semantic

narrowing instead of rejecting a config that was valid when written.

  • `workspace-context doctor` stops flagging relative paths inside fenced code blocks.
  • The stale-commands warning is emitted once per run and names the actual files.
  • The framework-graph build error names the install root, so the documented repair is run

where it works.

  • Research: a bibliographic-services reference covering per-service failure modes and the

OpenAlex citation-count trap, plus a shipped bibliography resolver and acquisition-obstacle recording.