Skip to content

feat(cli): serve guidance from the CLI, and stop dumping the whole surface - #1382

Draft
cristifalcas wants to merge 1 commit into
mainfrom
cf/agent-guidance-surface
Draft

feat(cli): serve guidance from the CLI, and stop dumping the whole surface#1382
cristifalcas wants to merge 1 commit into
mainfrom
cf/agent-guidance-surface

Conversation

@cristifalcas

Copy link
Copy Markdown
Contributor

aspect describe can answer what this repo's surface is. It could not answer
affordably, and it could not answer the question an agent actually has, which is
not "what tasks exist" but "how do I do this here".

The whole surface, every time. 186,669 bytes, all or nothing. --include
and --task narrow it; one task now costs 6,997. Omitted sections are absent
rather than empty — [] claims the repo has none, which is a different and
wrong answer. --task implies its own section unless --include is explicit.

Guidance is prose the CLI serves, resolved per repo. guidance(...)
declares a topic with a markdown body_file. describe carries a cheap index
with a byte count; --guidance=<id> returns one topic with its body. Bodies are
read only when a caller names the topic — reading every one to answer an index
request is the cost the split exists to avoid.

A repo can replace what a module shipped. ctx.guidance.add(guidance(...))
in config.axl, reusing an id to override. This is the property no static skill
file has: guidance that reflects this repo and versions with the binary
instead of rotting in a copied file. defined_in reports which declaration won.

Bodies are files rather than inline strings because a few hundred lines of prose
in a Starlark literal is neither reviewable nor diffable.

Also strips ANSI escapes from describeaspect delivery's description
carries \x1b[3m…\x1b[23m, and terminal formatting has no business in
machine-readable output.

Draft, because the form factor is a real question. MCP is not it: nobody
ships one inside their product CLI (GitHub, Azure, Netlify, Heroku, Stripe and
Sentry all ship siblings), and the industry serves guidance as Agent Skills and
reserves MCP for tools. The honest competitor is just shipping a skill, which
costs nothing to build and reaches every agent — but cannot resolve per-repo,
cannot be overridden by a customer's config.axl, and goes stale on its own
schedule. Those three are the entire argument for this. Design doc, including
the industry check and the case for stopping at a skill:
~/development/docs/2026-08-08-aspect-agent-guidance-surface-design.md.

The --include/--task filtering stands on its own merits and could land
separately if the guidance half doesn't survive review.


Changes are visible to end-users: yes

New aspect describe flags (--include, --task, --guidance), a new
guidance(...) AXL global, use_guidance in MODULE.aspect, and
ctx.guidance on config contexts. Existing aspect describe output is
unchanged when no flag is passed, apart from ANSI escapes no longer appearing.

Test plan

  • Filtering, section omission, ANSI stripping, the guidance index-vs-fetch
    split, and --guidance narrowing are covered by new unit tests.
  • Verified end to end against a scratch repo: index, fetch, config.axl
    override serving the repo's body with defined_in provenance, unknown ids
    exiting 2 with the valid list, and a wrong value type rejected by name.
  • Laziness proven rather than asserted: with a body chmod 000'd, the index
    still succeeds (bytes comes from metadata) and only the fetch reports
    Permission denied.

cargo test -p axl-runtime -p aspect-cli — 459 passed, 0 failed, no warnings.

🤖 Generated with Claude Code

…rface

#1377 made the surface answerable at runtime because Aspect's surface is
per-repo: `aspect <task>` means whatever that repo's `.aspect/*.axl` defines, so
it can never be in a training set. Opinions have the same property — a monorepo
with a go.work and vendored protos needs different guidance from a single-module
library — so they belong on the same mechanism.

`aspect describe` was answerable but not affordable: 186,669 bytes, all or
nothing. `--include=tasks,features,guidance` and `--task=<name>` narrow it, and
a single task now costs 6,997 bytes. Omitted sections are absent rather than
empty, because an empty array claims the repo has none, which is a different and
wrong answer. `--task` implies its own section unless `--include` is explicit.

`guidance(...)` declares a topic: id, title, summary, a markdown `body_file`,
`applies_to` hints and a stability. Bodies are files, not inline strings — a few
hundred lines of prose in a Starlark literal is neither reviewable nor diffable
— resolved and existence-checked at load, then read only when a caller names the
topic. `describe` carries a cheap index with a byte count; `--guidance=<id>`
returns one topic with its body. Discovery mirrors tasks: auto-discovered from
repo-local .axl, or declared with `use_guidance` in MODULE.aspect.

A `config.axl` contributes topics with `ctx.guidance.add(guidance(...))`, and
reusing an id replaces what a module shipped — which is the property no static
skill file can offer. `defined_in` reports which declaration won, so a collision
is visible rather than silent.

`Guidance` is plain Rust rather than a heap-mapped Starlark value: it owns only
Strings and PathBufs and nothing mutates it, so it needs none of Feature's
live/frozen split, tracing or thawing. Only the collection lives on the heap,
because Phase 2 configs append to it.

Also strips ANSI escapes from describe's prose. `aspect delivery`'s description
carries \x1b[3m…\x1b[23m, and terminal formatting has no business in
machine-readable output.

No `guidance_replace`: the collection resolves duplicate ids last-wins and
`Guidance` is immutable, so it would be `add` under a second name. The tips
precedent needs both only because a tip is mutable.

Design doc, including why not MCP and why an Agent Skill is the real
alternative: ~/development/docs/2026-08-08-aspect-agent-guidance-surface-design.md

axl-runtime + aspect-cli: 459 passed, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant