* docs: grounded spec for ao start bootstrapper + npm deprecation
Real-codebase-verified implementation spec (Track A: launcher + app-state
marker + release asset wiring). Replaces the somthing.md draft's aspirational
assumptions with file:line ground truth: correct bundle name (Agent
Orchestrator.app), publish repo (aoagents/agent-orchestrator), draft-release
+ asset-rename gaps, unsigned-build reality, and the already-wired
update-electron-app updater. Includes a dependency-ordered task breakdown
for AO execution.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: reframe spec around Go ao start subcommand (not a JS launcher)
The npm package ships the existing Go cobra CLI (backend/cmd/ao); this effort
rewrites the `ao start` subcommand to fetch+open the desktop app. Corrections:
- releases land on AgentWrapper/agent-orchestrator (aoagents was the temporary
rewrite home; forge publisher must be repointed)
- ao start stops starting the daemon; the frontend owns the daemon
- adds the real Go CLI command surface (1.7), the npm-delivery gap for the Go
binary (1.6), and the legacy first-boot import decision (6.4)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: separate prod vs test release targets in ao start spec
Dev/test loop must never cut a production release. Download repo + forge
publisher + npm scope are now build-time overridable:
- prod: AgentWrapper/agent-orchestrator + real package name
- test: harshitsinghbhandari/agent-orchestrator (fork) + @theharshitsingh/ao
T3/T5 now release+test against the fork and the test scope, with prod cut as a
separate gated step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(cli): rewrite ao start to fetch + open the desktop app (T1)
ao start no longer starts the daemon (the desktop app owns it). It now
resolves the installed app (~/.ao/app-state.json marker -> stat -> known-
location scan), fetches the latest release zip and ditto-unpacks it on macOS
when absent, opens it with --installed-via=npm-bootstrap, and prints an honest
deprecation notice. releaseRepo is build-time overridable (-ldflags) so test
builds fetch from the fork. Windows/Linux fetch/open are stubbed for T6/T7.
Review fixes folded in: download() copies deps.HTTPClient and drops its 2s
loopback-probe timeout (a real release asset is hundreds of MB), and fetchApp
clears ~/.ao/staging before unpacking. Regression test covers the timeout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(desktop): write ~/.ao/app-state.json marker on launch (T4)
The app is the sole writer of the marker ao start reads to locate the bundle.
New frontend/src/main/app-state.ts does an atomic temp+rename write mirroring
the daemon's runfile.Write, preserving installedAt/installSource across launches
and refreshing appPath/version/lastReconciledAt. main.ts hooks it into
app.whenReady ordered relocate (macOS) -> write marker -> createWindow, both
non-fatal. Bundle path is derived from process.execPath (not app.getAppPath,
which is the asar path); JSON keys match start.go's appState reader exactly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* ci(desktop-release): overridable repo, published release, stable asset aliases (T3)
Make the bootstrapper's constant releases/latest/download URL resolve:
- forge publisher repo reads AO_RELEASE_REPO (default AgentWrapper/agent-
orchestrator); the workflow sets it to github.repository so a fork run
publishes to the fork and never to prod
- draft:false so the release is immediately live (constant URL needs it)
- add ubuntu-latest to the matrix (issue #2191)
- post-publish steps upload stable space-free aliases
(agent-orchestrator-darwin-arm64.zip, agent-orchestrator-win32-x64.exe)
matching exactly what start.go fetches
Review fix: the alias upload targeted GITHUB_REF_NAME (the git tag), but
publisher-github creates the release as v<package.json version>; retargeted to
that and relaxed the guard so workflow_dispatch also produces aliases.
Known gaps (documented inline): macOS x64 needs an Intel runner (macos-latest is
arm64-only); the Linux stable asset name awaits the deb/rpm-vs-AppImage decision.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: format with prettier [skip ci]
* feat(npm): deliver Go ao binary as @aoagents/ao via per-platform packages (T2)
Ship the ao CLI to npm with ZERO install scripts using the esbuild model:
- packages/ao: pure-JS @aoagents/ao with a bin/ao.js shim that resolves and
execs the matching @aoagents/ao-<platform>-<arch> optionalDependency
- four platform packages (darwin-arm64/x64, win32-x64, linux-x64), each os/cpu
gated so npm installs only the host's; binary cross-compiled CGO-free
(modernc.org/sqlite), gitignored, shipped via files
- build-binaries.sh cross-compiles all four; releaseRepo keeps its prod default
Not added as root workspaces on purpose: os/cpu-restricted members make root
`npm ci` fail EBADPLATFORM (CI's api-drift job runs it). Packages publish
standalone; the shim was verified in a published-like layout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(npm): set @aoagents/ao packages to 0.10.0 (above existing 0.9.5)
The existing @aoagents/ao on npm is 0.9.5; the launcher must publish a higher
version so npm latest advances and existing users get the new fetch-and-open
binary on update. All five packages plus the four optionalDeps pins set to
0.10.0.
* chore: format with prettier [skip ci]
* fix(start): capture install provenance before macOS relocation
moveToApplicationsFolder() relaunches the app from /Applications without
forwarding the --installed-via arg, and code past a successful move never
runs in the staging instance. The post-move instance therefore wrote
installSource="unknown", and writeAppStateMarker's sticky logic then locked
it there, losing the npm-bootstrap provenance in the exact path it exists for.
Write the marker before relocation when --installed-via is present so the
source is persisted while the arg is still available; the post-move launch
preserves it (sticky installSource) while refreshing appPath to /Applications.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: format with prettier [skip ci]
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* feat(frontend): add live browser panel
* chore: format with prettier [skip ci]
* feat: preserve and auto-open browser previews
* fix: retry browser preview after session updates
* fix: wait for browser view before preview navigation
* fix: reopen preview after session switches
* fix: preserve browser views across session switches
* chore: format with prettier [skip ci]
* feat: add `ao preview` command to drive the session browser panel
Replaces the browser panel's auto-detect with an explicit, session-scoped
command. `ao preview [url]` runs inside a session (derives the target from
AO_SESSION_ID; rejects when unset or when the session is unknown):
- with a url, opens it verbatim (file://, http, https; no sanitization for now)
- with no url, autodetects index.html in the workspace as before
The resolved target is persisted as a new `previewUrl` session field and fans
out over the existing CDC /events stream (the sessions update trigger now fires
on preview_url and carries previewUrl in its payload). The desktop browser panel
reflects session.previewUrl: it opens, switches the center pane to the browser,
and navigates, re-navigating only when the target changes.
ponytail: file:// preview targets are accepted unsanitized; agent-trusted for now.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(cli): document the `ao preview` command
Add `ao preview` to the CLI command tables in README.md and docs/cli/README.md,
noting it resolves its session from AO_SESSION_ID and its no-arg autodetect vs
explicit-URL behavior.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: format with prettier [skip ci]
* fix(frontend): reveal `ao preview` in the inspector Browser tab, not the center pane
`ao preview` set session.previewUrl, and SessionView surfaced it by
popping the browser into the center pane, replacing the terminal. Reveal
it in the inspector rail's Browser tab instead (opening the rail if it is
collapsed); the manual pop-out button still expands it to the center.
Lifts the inspector's active tab to an optional controlled prop so
SessionView can drive it, and adds a regression test asserting the center
pane keeps the terminal while the rail switches to Browser.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: instruct agents to `ao preview` when showing frontend changes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Vaibhaav <user@example.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Harshit Singh Bhandari <dev@theharshitsingh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* docs: refocus README on the product, move progress to docs/STATUS.md
Rework the README around what ReverbCode is and does, drawing the
agent/runtime/tracker framing and the "how it works" flow from the legacy
agent-orchestrator README but stating only what the rewrite's code actually
implements (zellij runtime, GitHub SCM/tracker, 23 verified agent adapters,
port/adapter extensibility surface).
Move progress tracking out of the README: rename docs/status.md to
docs/STATUS.md, reconcile the README's "Status and roadmap" content into it
(SCM observer issue refs, milestone link), correct the adapter count to 23,
and drop the stray trailing markup. Update the README, AGENTS.md, docs/README.md,
and docs/stack.md references accordingly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: format with prettier [skip ci]
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* docs: sync documentation with current state of main
The rewrite is further along than several docs claimed. Bring the docs
in line with the actual code on main:
- status.md: rewrite the stale "session HTTP routes not wired yet" /
"next integration work" framing into a shipped vs in-flight breakdown.
- cli/README.md: document the full product command surface (project,
session, spawn, send, orchestrator) instead of "not present yet".
- architecture.md: correct the package layout (service/{pr,review},
observe/scm, observe/reaper, daemon, config) and add the no_signal
status to the derivation precedence.
- backend-code-structure.md: add service/review and observe/scm.
- README.md: expand the agent-adapter list (20+), add project set-config,
and describe the frontend as the real wired supervisor it is.
- AGENTS.md / docs/README.md: drop "placeholder frontend" wording and
add the agent-adapter doc to the index.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: format with prettier [skip ci]
Add an "Electron app (dev)" section: npm install + npm run dev under
frontend/, with the explicit heads-up that the app does not start the
daemon — it attaches over loopback to a daemon started via `ao start`
(plus npm run dev:web for renderer-only work in a browser).
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* chore: add prettier config and CI auto-formatter
Adds .prettierrc and .prettierignore (config only, no local enforcement).
Formatting runs in CI via the prettier.yml workflow: on every push to a
non-main branch, Prettier rewrites changed files and commits the result back
using GITHUB_TOKEN. Developers never need to run Prettier locally.
Intentionally excludes husky/lint-staged — local pre-commit hooks are the
wrong layer for a formatter that the whole team doesn't need installed.
Also adds .envrc.local to .gitignore for personal local shell overrides.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 27336650d2ee
* chore: format with prettier [skip ci]
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* feat(backend): HTTP daemon skeleton — config, health, runfile, graceful shutdown (#10)
Phase 1a of the Go HTTP daemon lane (#10). Stands up the loopback-only
sidecar skeleton the later REST/SSE/WS/static surfaces build on:
- config: env-driven (AO_HOST/PORT/ENV/timeouts/run-file) with zero-config
defaults; binds 127.0.0.1:3001; validates and fails fast on bad input.
- httpd: chi router with the recoverer → request-id → logger → real-ip
middleware stack and /healthz + /readyz probes. Per-request timeout is
carried in config but intentionally not global — it scopes to /api/v1 in
Phase 1b so it never throttles SSE/WS/health.
- runfile: atomic PID + port handshake (running.json) for the Electron
supervisor, with a dead-PID stale check so a crashed predecessor doesn't
block startup while a live one fails fast.
- server: bind-before-publish (port conflict fails fast), graceful shutdown
on SIGINT/SIGTERM via signal.NotifyContext with a 10s hard timeout, and
run-file cleanup on exit.
Why: the daemon must be safely supervisable as a child process — the
supervisor needs a discoverable PID/port and the daemon must not leave a
half-started process or stale handshake behind. Locking the lifecycle down
now keeps the future port split a small change rather than a rewrite.
Tests cover config defaults/overrides/validation, run-file round-trip and
live/dead PID detection, health probes, full Run lifecycle, and port-conflict
fail-fast.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* refactor(backend): drop Env config field — not needed yet (#10)
Per review on #14: AO_ENV / Config.Env / IsProduction() weren't load-bearing
for Phase 1a — they only switched the slog handler. Removing them now keeps
the surface minimal; the env knob can come back later when a real consumer
needs it.
- config: remove Env field, AO_ENV parsing, and IsProduction helper.
- main: collapse newLogger to a single text-handler path.
- httpd: drop the env field from the listening log line.
- tests: drop the env assertions and AO_ENV fixture.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs: add backend run + config quick-start to README (#10)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(backend): address Phase 1a review comments (#10)
- config: drop AO_HOST entirely — the daemon is loopback-only by design,
so making the bind host env-configurable was a security footgun
- config: use net.JoinHostPort in Addr() so IPv6 literals stay valid
- config: reject zero/negative AO_REQUEST_TIMEOUT and AO_SHUTDOWN_TIMEOUT
(time.ParseDuration accepts both; either would silently break the
daemon — instant request expiry / no graceful drain)
- runfile: split processAlive into unix/windows build-tagged files so
liveness detection is reliable on both platforms (Windows uses
OpenProcess; POSIX keeps signal 0)
- runfile: document os.Rename overwrite semantics (atomic on POSIX,
REPLACE_EXISTING on Windows) so the temp-then-rename pattern's
cross-platform behaviour is explicit
- httpd tests: give probe/waitForHealth clients an explicit per-request
timeout so a stalled connect can't hang the test on the outer deadline
* fix(backend): strip trailing blank line from runfile.go (#10)
gofmt CI was failing because removing the orphan processAlive doc
comment left an extra newline at EOF.
* fix(backend): cross-platform run-file replace + AO_HOST rationale (#10)
- runfile: introduce build-tagged atomicReplace — POSIX rename(2) on
Unix, MoveFileEx with MOVEFILE_REPLACE_EXISTING on Windows. The Go
runtime happens to do the Windows call internally already, but
invoking it directly makes the cross-platform contract explicit
instead of a runtime implementation detail
- runfile: tighten process_unix.go build tag from `!windows` to `unix`
so plan9/js/wasm fail to build rather than silently using a broken
signal-0 probe
- runfile: add TestWriteOverwritesExisting covering the stale run-file
replace path that none of the previous tests exercised
- config: anchor the loopback-only decision in the LoopbackHost doc so
the next contributor doesn't reintroduce AO_HOST without the security
rationale
* fix(backend): route chi access logs through slog/stderr (#10)
chi's middleware.Logger writes via stdlib log to stdout, but the
daemon's slog logger writes to stderr — so REST traffic and daemon
logs landed on different streams in different formats. Replace it
with a small slog-backed requestLogger that:
- Wraps the response writer via middleware.NewWrapResponseWriter so
status/bytes are accurate even when handlers return without an
explicit WriteHeader.
- Reads the request id off the context set by middleware.RequestID
(kept mounted just before this middleware so the id is available).
- Emits one structured Info line per request with method, path,
status, bytes, duration, and remote — same key=value shape as the
rest of the daemon, one stream for the Electron supervisor to
capture.
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Add docs/ for newcomers: an index, an architecture deep-dive (the
OBSERVE→DECIDE→ACT loop, the canonical state model, the package layout, every
component, and the load-bearing invariants), and a status/roadmap (what's done
PR-by-PR, what's left, the integration to-dos + carried-forward items, the open
cross-lane contract questions, and where to plug in). Link them from the README.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Initial buildable skeleton for the agent-orchestrator rewrite, splitting
the repo into a Go backend daemon and an Electron + TypeScript frontend.
- backend/: go.mod (Go 1.22) + main.go that compiles and prints a startup line
- frontend/: package.json, strict tsconfig.json, Electron main-process stub
- .gitignore for Node/Electron/Go/OS/editor/env artifacts
- README note describing the new two-folder structure
No app logic or architecture layering yet (routes/controllers/services/etc.
come in a later task). go build and tsc --noEmit both pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>