Skip to content

feat: add ataegina ports --json (agent-native slot output)#27

Merged
noahhyden merged 3 commits into
mainfrom
feat/json-ports
Jul 19, 2026
Merged

feat: add ataegina ports --json (agent-native slot output)#27
noahhyden merged 3 commits into
mainfrom
feat/json-ports

Conversation

@noahhyden

Copy link
Copy Markdown
Owner

What & why

First of five agent-native CLI additions (see docs/design/agent-native.md). Ataegina's audience is coding agents running fleets of worktrees; they parse output programmatically, so the human table in ports is friction. This adds ataegina ports --json.

ataegina ports --json prints a single line of JSON — the shared slot object the rest of the surface (status, up --json, list --json) will reuse:

{"index":1,"repo_root":"/abs/wt","frontend":{"port":5174,"url":"http://localhost:5174"},"backend":{"port":8001,"url":"http://localhost:8001"},"log_dir":"/tmp/ate-wt1","db":{"name":"myapp_wt1","url":"postgres://localhost:5432/myapp_wt1"}}
  • db is null when no database is configured; db.url is null when DB_NAME is set without a DB_URL_TEMPLATE.
  • Plain ports (no flag) keeps its human output unchanged.
  • Two reusable helpers land here: json_str (bash-3.2-safe JSON string escaper, backslash-first ordering) and emit_slot_json.

Discipline

  • Spec: docs/design/agent-native.md (covers all 5 features).
  • Tests-first: tests/ports_json.bats — 11 hermetic tests (shape, per-worktree ports, db variants, quote/backslash escaping stays valid JSON, human-output regression, completion advertises the flag).
  • Live verification: exercised the real binary end-to-end, piped through python -m json.tool for primary + worktree ataegina: add move command + report what down stops #1 with a DB configured.
  • Mutation red-teaming: 3 deliberate mutations (db-always-null, skip backslash-escape, index-as-string) — each caught by a distinct test.
  • Docs: README command table, man page, CHANGELOG, bash+zsh completion.
  • No new dependencies; single bash file preserved.

🤖 Generated with Claude Code

noahhyden and others added 3 commits July 19, 2026 18:26
Print this worktree's derived slot as a single line of JSON — index,
repo_root, frontend/backend port+url, log_dir, and the per-worktree
database name+url when configured — so coding agents and scripts can
parse it directly instead of scraping the human table.

Introduces two reusable emitters the rest of the agent-native surface
(status, up --json, list --json) will build on: json_str (a bash-3.2-safe
JSON string escaper) and emit_slot_json (the shared slot object). `db` is
null when no database is configured; db.url is null when DB_NAME is set
without a DB_URL_TEMPLATE.

Spec: docs/design/agent-native.md. Completion (bash+zsh), man page,
README, and CHANGELOG updated. New hermetic suite tests/ports_json.bats
(11 tests) covers the shape, per-worktree ports, the db variants, JSON
escaping of quotes/backslashes in paths, and the human-output regression.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Compare repo_root against the git-resolved toplevel instead of the raw
mktemp path. On macOS CI $TMPDIR is /var -> /private/var (a symlink) and
git rev-parse --show-toplevel resolves it, so the raw-path comparison
failed on both macOS jobs while passing on Linux/Windows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@noahhyden
noahhyden merged commit b21aa14 into main Jul 19, 2026
8 checks passed
@noahhyden
noahhyden deleted the feat/json-ports branch July 19, 2026 23:11
noahhyden added a commit that referenced this pull request Jul 20, 2026
Compare repo_root (and the human list path) against git's resolved toplevel
via a resolved() helper, not the raw mktemp path. On macOS CI $TMPDIR is
/var -> /private/var (a symlink) which git rev-parse resolves, so the raw
comparison failed on both macOS jobs (tests 1/2/3/7) while passing on
Linux/Windows. Same class as the PR #27 fix; now applied to this file too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
noahhyden added a commit that referenced this pull request Jul 20, 2026
* feat: add `ataegina list --json` (fleet view for supervising agents)

Emit the registry as a JSON array — the shared slot shape per worktree
(primary at index 0 first, then each registry entry) plus two list-only
fields: `stale` (its directory is gone) and `live` (a coarse best-effort
"a derived port is listening"; always false under a `none` port backend).
This is the fleet view a supervising agent uses to see all its parallel
workers at once. Human `list` output is unchanged.

`list` becomes cmd_list; _ate_list_entry_json computes a slot for an
arbitrary (index, path) from the repo's config (port bases, DB naming)
rather than the current tree, reusing emit_db_json for the per-entry db
object. This completes the five-part agent-native surface.

Spec: docs/design/agent-native.md. Completion (bash+zsh), man page, README,
CHANGELOG, and in-script --help updated. New hermetic suite
tests/list_json.bats (10 tests): the array shape, per-worktree ports, stale
(a removed worktree dir), live (fake `ss` on a derived port), per-worktree
db naming, the single-primary case, human-output regression, arg validation,
completion. Completion assertions across ports/status/list made robust to
future group changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test: fix list --json path assertions for macOS symlinked $TMPDIR

Compare repo_root (and the human list path) against git's resolved toplevel
via a resolved() helper, not the raw mktemp path. On macOS CI $TMPDIR is
/var -> /private/var (a symlink) which git rev-parse resolves, so the raw
comparison failed on both macOS jobs (tests 1/2/3/7) while passing on
Linux/Windows. Same class as the PR #27 fix; now applied to this file too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <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