feat(aterm): rebuild the branded session launcher, and retire aosterm #1240

Merged
coilyco-ops merged 3 commits from aos/claude/vk48 into main 2026-08-25 21:07:53 +00:00
Owner

aosterm had never been run once. Shell history carries 846 acompose
invocations against zero for it, while CI built and tested it on every push.

It had also drifted off its own contract. It invoked aoscompose <role> <seat>
positionally against a CLI that takes --role/--agent, so the role was
silently dropped and the launch converged a stray session shadow instead of
starting the requested agent.

What aterm is

The windowed sibling of the acompose shell function, running the same native
runtime rather than the container path: a leased session shadow wrapping
agent-compose launch. acompose takes over the terminal you typed in, aterm
leaves it free. Alacritty stays the target.

aterm                              # pick a role, then a seat
aterm platform                     # the role's default seat
aterm platform codex -- --resume   # arguments for the harness
aterm --list                       # the live roster, no window

Two silent-failure holes closed

Alacritty closes the window the instant its child exits, so a failing launch
used to vanish before anyone could read it. The child now runs through an inner
_session stage that passes the exit code through and holds the window on any
non-zero exit. --hold also holds after a clean exit.

The launcher watches the terminal for a startup failure rather than detaching
blind, so "no window appeared" comes back as a message naming the cause.

Stale roles are refused before anything opens

The roster is read live from agent-compose catalog roles --json on every run.
A role that left the roster is refused with a near-miss suggestion and the live
slugs listed. Shell history is full of engineer, ops, creator, and strats
against a live roster of seven, so this is the failure it catches most.

A seat is checked twice: it has to belong to the role, and it has to be a
harness agent-compose launch can start. A catalogue seat like penpot is real
but not launchable, and the refusal says which of the two it failed.

Notes

  • docs/agent-terminal-native.md becomes docs/aterm.md and absorbs the
    launcher sections that were duplicated in warp-host-setup.md. The docs count
    sits at its band cap, so this renames in place rather than adding a page.
  • The acompose shell function is unchanged. The two names now mean two
    different things rather than one shadowing the other.
  • Annotation assertions derive from the fixture rather than spelling a role
    title, so an upstream retitle stops reading as a launcher regression.
  • Release plumbing ships one aterm-* binary where there were two, and the
    release smoke check now also asserts the off-roster refusal.

Verified: pre-commit run --all-files, just aterm-test (48 cases, 75%
coverage), 716 pytest tests, and a real branded window launched end to end
against fixture stubs.

🤖 Generated with Claude Code

`aosterm` had never been run once. Shell history carries 846 `acompose` invocations against zero for it, while CI built and tested it on every push. It had also drifted off its own contract. It invoked `aoscompose <role> <seat>` positionally against a CLI that takes `--role`/`--agent`, so the role was silently dropped and the launch converged a stray session shadow instead of starting the requested agent. ## What `aterm` is The windowed sibling of the `acompose` shell function, running the same native runtime rather than the container path: a leased session shadow wrapping `agent-compose launch`. `acompose` takes over the terminal you typed in, `aterm` leaves it free. Alacritty stays the target. ```text aterm # pick a role, then a seat aterm platform # the role's default seat aterm platform codex -- --resume # arguments for the harness aterm --list # the live roster, no window ``` ## Two silent-failure holes closed Alacritty closes the window the instant its child exits, so a failing launch used to vanish before anyone could read it. The child now runs through an inner `_session` stage that passes the exit code through and holds the window on any non-zero exit. `--hold` also holds after a clean exit. The launcher watches the terminal for a startup failure rather than detaching blind, so "no window appeared" comes back as a message naming the cause. ## Stale roles are refused before anything opens The roster is read live from `agent-compose catalog roles --json` on every run. A role that left the roster is refused with a near-miss suggestion and the live slugs listed. Shell history is full of `engineer`, `ops`, `creator`, and `strats` against a live roster of seven, so this is the failure it catches most. A seat is checked twice: it has to belong to the role, and it has to be a harness `agent-compose launch` can start. A catalogue seat like `penpot` is real but not launchable, and the refusal says which of the two it failed. ## Notes - `docs/agent-terminal-native.md` becomes `docs/aterm.md` and absorbs the launcher sections that were duplicated in `warp-host-setup.md`. The docs count sits at its band cap, so this renames in place rather than adding a page. - The `acompose` shell function is unchanged. The two names now mean two different things rather than one shadowing the other. - Annotation assertions derive from the fixture rather than spelling a role title, so an upstream retitle stops reading as a launcher regression. - Release plumbing ships one `aterm-*` binary where there were two, and the release smoke check now also asserts the off-roster refusal. Verified: `pre-commit run --all-files`, `just aterm-test` (48 cases, 75% coverage), 716 pytest tests, and a real branded window launched end to end against fixture stubs. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aosterm had never been run once: 846 acompose invocations in shell history
against zero for it, while CI built and tested it on every push. It had also
drifted off its own contract, invoking `aoscompose <role> <seat>` positionally
against a CLI that takes --role/--agent, so the role was silently dropped and
the launch converged a stray session shadow instead.

aterm replaces it and is the windowed sibling of the acompose shell function,
running the same native runtime rather than the container path: a leased
session shadow wrapping `agent-compose launch`.

Two silent-failure holes are closed. Alacritty closes the window the instant
its child exits, so a failing launch used to vanish unread; the child now runs
through an inner `_session` stage that passes the exit code through and holds
the window on any non-zero exit. The launcher also watches the terminal for a
startup failure rather than detaching blind, so "no window appeared" comes back
naming the cause.

The roster is read live from `agent-compose catalog roles --json` on every run.
A role that left the roster is refused before anything opens, with a near-miss
suggestion and the live slugs listed. A seat is checked both for belonging to
the role and for being a harness `agent-compose launch` can start. A bare
`aterm` picks interactively instead of failing.

Alacritty stays the target and Warp is not involved. docs/agent-terminal-native.md
becomes docs/aterm.md, absorbing the launcher sections that were duplicated in
warp-host-setup.md; the docs count is at its band cap, so this renames in place
rather than adding a page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: platform
merge origin/main into the aterm rebuild
Some checks failed
ci / aos-cli-tests (pull_request) Failing after 20s
ci / aos-eval-tests (pull_request) Successful in 6s
ci / ward-doctor (pull_request) Successful in 10s
ci / gate (pull_request) Successful in 53s
dev-base-pr / build (pull_request) Successful in 2m4s
13f511117e
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: platform
fix(aterm): pin a working directory in the tests, and assert the refusal reason
All checks were successful
ci / aos-eval-tests (pull_request) Successful in 9s
ci / ward-doctor (pull_request) Successful in 6s
ci / aos-cli-tests (pull_request) Successful in 25s
ci / gate (pull_request) Successful in 1m9s
dev-base-pr / build (pull_request) Successful in 5m56s
fdef479818
The tests inherited aterm's default working directory, which is $PROJECTS_ROOT
or ~/projects. No CI container has one, so eight cases failed on a missing
/root/projects rather than on anything they were testing.

The release smoke check had the same weakness in its stale-role case: it only
asserted a non-zero exit, which the same missing directory would have produced.
It now pins the directory and greps for the refusal itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: platform
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1240
No description provided.