Design: Onboarding Friction Reduction

PR: feat/onboarding-improvements Author: Suraj + Claude Date: 2026-03-13

Motivation

New users hitting Agent Orchestrator for the first time faced multiple friction points that could cause them to abandon setup before ever spawning an agent. The goal of this PR is to make the path from npm install or git clone to ao spawn as smooth as possible — ideally zero interruptions. Fixes cover both the npm install path and the source/contributor path.

Problems Identified

#ProblemSeverityWho it affects
1 setup.sh crashes with EACCES on npm link Blocking Every macOS user
2 ao init asks 13 prompts before generating config High friction Every new user
3 Adding a second project requires editing YAML by hand High friction Multi-project users
4 ao start crashes if configured port is busy Medium friction Users running other dev servers
5 --smart flag shows "coming soon" placeholder Low friction Users exploring CLI flags
6 Same npm link bug in ao update and ao doctor --fix Blocking Users updating or diagnosing
7 No "what's next" guidance — user doesn't know what to run or where Medium friction Every new user
8 ao start crashes for npm users — @composio/ao-web (dashboard) was never published Blocking Every npm user
9 npm install -g fails with EACCES on default macOS Node — no guidance provided High friction npm users on macOS
10 Dashboard production server uses npx next start — slow global lookup, may download Next.js at runtime Medium friction npm users
11 findWebDir() returns a nonexistent path instead of throwing — error message says "Run: pnpm install" (wrong for npm users) Medium friction npm users when package resolution fails
12 setup.sh / ao-update.sh — non-interactive npm link failure exits 0 (CI sees green, ao not linked) Medium friction CI pipelines
13 detectDefaultBranch duplicated in init.ts and add-project.ts — bug fixes won't propagate Low friction Maintainers

Changes

1. Fix npm link permission error

Before

npm link fails with EACCES on macOS. Script exits. User is stuck with no ao command and no guidance.

After

Tries npm link first. If it fails and terminal is interactive, auto-retries with sudo. If non-interactive (CI), prints the manual command and exits with code 1.

npm link retry logic
Run npm link
Success?
YES
Done ✓
NO (EACCES)
Interactive terminal?
YES
Retry with sudo npm link
Done ✓
NO (CI)
Print manual fix + exit 1

2. Make ao init default to auto-detection

Before

ao init → 13 interactive prompts
ao init --auto → zero prompts

Most users should use --auto but it wasn't the default.

After

ao init → auto-detects everything, zero prompts
ao init --interactive → full wizard for manual control

ao init decision flow
User runs ao init
--interactive flag?
NO (default)
Auto-detect git remote, branch, language, framework
Generate config + agent rules from templates
Write agent-orchestrator.yaml
YES
13-prompt interactive wizard
User manually configures each setting
Write agent-orchestrator.yaml

3. Add ao add-project <path> command

Before

Adding a project meant opening agent-orchestrator.yaml and manually writing YAML with the correct structure, session prefix, and repo format.

After

One command: ao add-project ~/Desktop/mono

The command automatically:

  1. Resolves the path and finds the existing config
  2. Detects git remote (owner/repo)
  3. Detects default branch (main/master/etc.)
  4. Generates a unique session prefix (validates against existing ones)
  5. Detects project type (language, framework, test runner)
  6. Generates agent rules from templates
  7. Appends the project to the config
ao add-project pipeline
Resolve
path
Find existing
config
Detect git
remote
Detect default
branch
Generate unique
session prefix
Detect project
type
Generate
agent rules
Append to
config

4. Auto-find free port on ao start

Before

Port 3000 is already in use.
Free it or change 'port' in agent-orchestrator.yaml.

After

Port 3000 is busy — using 3001 instead.
ao start — port resolution
Read port from config (default: 3000)
Port available?
YES
Start on configured port
NO
Scan port+1 … port+20
Free port found?
YES
Start on free port
Log: "Port X busy — using Y"
NO
Error: no free port in range

5. Remove --smart placeholder

Before

ao init --auto --smart showed "AI-powered rule generation not yet implemented". A dead feature flag.

After

Removed entirely. Template-based rules are the default and work well.

6. Contextual "next step" hints with directory guidance

Before

After each command completes, user gets either no guidance or a generic message like "Next: ao start". No indication of where to run the next command — users frequently ran ao init inside the agent-orchestrator repo instead of their project.

After

Every command prints a clear "what's next" block that tells the user exactly what to run and from which directory. Each step chains into the next, creating a guided path through the entire flow.

Guided handoff chain — each command tells you the next
setup.sh completes
Prints:
cd ~/your-project
ao init
ao init completes
Prints: (from this directory: ~/your-project)
ao start
ao add-project ~/other-repo
ao start completes
Prints:
ao spawn my-project <issue-number>
User is productive ✓

Example output after setup.sh:

Setup complete!

What's next:

  Navigate to your project directory and initialize:

    cd ~/your-project
    ao init            # auto-detects everything, zero prompts

  Then start the orchestrator + dashboard:

    ao start            # run this from your project directory

  Want to add more projects later?

    ao add-project ~/path/to/another-repo

7. Publish @composio/ao-web dashboard on npm

This was the single biggest blocker for npm users. Every other AO package was published on npm, but the dashboard — the package that ao start needs to launch the web UI — was never published. npm users hit an immediate fatal crash.

Root cause: 5 blockers preventing publishing

#BlockerWhy it existedFix
1 "private": true in package.json Dashboard was never intended as a standalone npm package Removed the flag
2 In changeset ignore list Excluded from versioning/publishing pipeline Moved to linked array so it versions with other packages
3 Dev-only server (pnpm run dev via concurrently) Used tsx watch for TypeScript — doesn't work outside monorepo Created production entry point (start-all.ts → compiled to dist-server/)
4 node-pty as hard dependency Native C++ addon — fails to compile without build tools (Python, make, gcc) Moved to optionalDependencies with dynamic import + graceful fallback
5 Cross-boundary imports server/terminal-observability.ts imported from ../src/lib/ — breaks when compiled Moved resolveProjectIdForSessionId to @composio/ao-core

What the user experienced

Before

$ npm install -g @composio/agent-orchestrator
$ ao start
Error: Could not find @composio/ao-web package.
Run: pnpm install

Fatal crash. The suggested fix (pnpm install) doesn't work for npm users. Complete dead end — dashboard was simply not available outside the monorepo.

After

$ npm install -g @composio/agent-orchestrator
$ ao start
✓ Dashboard starting on http://localhost:3000
✓ Lifecycle worker started
✓ Orchestrator session created

Next step:
  ao spawn my-project <issue-number>

Package size optimization

The initial npm pack of @composio/ao-web was 67 MB — Next.js dumps build cache, trace files, and source maps into .next/. We optimized the files field to include only what's needed at runtime:

npm package size — @composio/ao-web
Naive "files": [".next"]
67 MB
67 MB
Optimized files field
1 MB
1 MB

The optimized files field includes only:

"files": [
  ".next/server",          // compiled server pages + API routes
  ".next/static",          // client-side JS/CSS bundles
  ".next/*.json",          // build manifest, routes manifest
  ".next/BUILD_ID",        // build identifier
  "dist-server",           // compiled terminal WebSocket servers
  "next.config.js"         // Next.js configuration
]

Excluded: .next/cache/ (build cache, 60+ MB), .next/trace (webpack trace files), source TypeScript files.

Production architecture

In the monorepo, the dashboard runs via concurrently with tsx watch (hot reloading). On npm, we need pre-compiled servers. start-all.ts is the production entry point that spawns 3 processes:

start-all.js — production process tree
node dist-server/start-all.js
Parent process (manages lifecycle + graceful shutdown)
Next.js
node_modules/.bin/next start
Dashboard UI on PORT
Terminal WS
terminal-websocket.js
ttyd proxy on TERMINAL_PORT
Direct Terminal
direct-terminal-ws.js
node-pty on DIRECT_TERMINAL_PORT

How the CLI decides: dev vs production

The CLI needs to work in both the monorepo (for contributors) and as an npm package (for users). It detects the mode by checking whether the server/ source directory exists — present in the monorepo, absent in the published npm package (only dist-server/ ships).

ao start — dev vs production detection
ao start
Locate @composio/ao-web via require.resolve or monorepo fallback
server/ source dir exists?
YES (monorepo/source)
pnpm run dev
tsx watch + HMR + concurrently
Dev mode ✓
NO (npm package)
node dist-server/start-all.js
pre-compiled, no dev deps needed
Production mode ✓

End-to-end npm user journey

What happens when an npm user runs ao start
npm install -g @composio/agent-orchestrator
npm installs @composio/ao-cli + all plugin deps + @composio/ao-web
workspace:* auto-converted to real versions by pnpm publish
ao start https://github.com/org/repo
Clone repo → auto-generate config → find free port
findWebDir() resolves @composio/ao-web from node_modules
server/ exists?
NO → production mode → node dist-server/start-all.js
Spawns Next.js + terminal servers + orchestrator tmux session
Dashboard live on http://localhost:3000 ✓

Impact

Fatal crash
Works
ao start for npm users
67 MB
1 MB
npm package size
0
2
Startup modes (dev + production)

8. Add EACCES permission guidance for npm users

Before

npm install -g @composio/agent-orchestrator fails with EACCES on macOS default Node installs. User gets a wall of error text with no actionable fix.

After

README and SETUP.md document 3 options: sudo npm install -g (quick fix), npx @composio/agent-orchestrator (no install), or fix the npm prefix directory (permanent). npm is now listed as Option A (recommended) in README.

9. Use local Next.js binary in production

Before

start-all.ts launched the dashboard with npx next start. npx does a global PATH lookup and, if next isn't found, tries to download it at runtime — adding 30+ seconds or failing on slow/offline networks.

After

Uses the local binary directly: node_modules/.bin/next. Instant startup, no network dependency.

10. Fix findWebDir() error handling

Before

findWebDir() silently returned a nonexistent path when all resolution methods failed. The caller then showed "Could not find @composio/ao-web. Run: pnpm install" — wrong advice for npm users.

After

findWebDir() throws with install-specific guidance: npm install -g for npm users, pnpm install && pnpm build for source users. Redundant checks in start.ts and dashboard.ts removed.

11. Fix CI-silent failure in setup scripts

Before

In non-interactive mode, npm link failure printed a message but the script continued with exit code 0. CI pipelines saw green while ao was not actually linked.

After

Non-interactive npm link failure now calls exit 1, making CI pipelines correctly report the failure.

12. Deduplicate detectDefaultBranch

Before

The same 30-line function (3-method fallback: symbolic-ref → GitHub API → local refs) was copy-pasted in both init.ts and add-project.ts. Bug fixes to one wouldn't propagate to the other.

After

Single implementation in packages/cli/src/lib/git-utils.ts, imported by both commands.

Known Limitations

The following issues were investigated and determined to not need fixes:

IssueVerdictReason
node-pty optional — terminal panels broken? Not an issue Main terminal view uses ttyd (iframe), not node-pty. Direct terminal is a separate feature that degrades gracefully with a server-side log.
Git remote regex is GitHub-only By design AO only ships GitHub SCM/tracker plugins. Non-GitHub repos would fail at ao spawn anyway. A warning could be added later.
start-all.ts cleanup doesn't wait for children Not an issue Children are independent OS processes that handle SIGTERM on their own. next start is read-only (no cache writes). On Ctrl+C, the terminal sends SIGINT to the entire process group regardless.
ao add-project crashes on malformed YAML Acceptable The yaml library produces readable errors with line/column numbers. Same pattern as loadConfig() in core. Not worth a special wrapper.
ao add-project non-atomic write Not an issue writeFileSync is effectively atomic for small files (config is well under the OS block size). Same pattern used everywhere in the codebase.
EACCES on npm install -g is docs-only Unfixable The error happens inside npm before any of our code runs. A postinstall script only executes after successful install. Documentation is the correct mitigation.

New Onboarding Flow

npm install path (most users)

Before (5+ min, multiple failure points)

1
git clone ...
Required even for non-contributors
2
bash scripts/setup.sh
Could crash on npm link
3
cd ~/my-project && ao init
13 interactive prompts
4
nano agent-orchestrator.yaml
Edit YAML to add projects
5
ao start
Could crash on port conflict
6
ao spawn my-project 123
User has to remember this themselves

After (under 1 min, fully guided)

1
npm install -g @composio/agent-orchestrator
One command, no clone needed
2
ao start https://github.com/org/repo
Clones, configures, and launches — prints "ao spawn"
3
ao spawn my-project 123
Start working!

Source install path (contributors)

Before

1
bash scripts/setup.sh
Could crash on npm link. No next-step guidance.
2
cd ~/my-project
User has to figure out "where do I go?" on their own
3
ao init
13 interactive prompts
4
ao start
Could crash on port conflict

After (guided)

1
bash scripts/setup.sh
Handles permissions + prints "cd ~/your-project && ao init"
2
cd ~/my-project && ao init
Zero prompts + prints "ao start" with directory context
3
ao start
Auto-finds free port + prints "ao spawn <project> <issue>"
4
ao spawn my-project 123
Start working!

UX Impact

Before vs After — Quantitative Metrics
Prompts in ao init
Before
13
After
0
Steps to ao spawn
Before
6+
After (npm)
3
Fatal crash points
Before
3
After
0
Manual config edits
Before
Yes
After
No
Dead CLI flags
Before
1
After
0
13
0
Prompts in ao init
6+
3
Steps to first ao spawn (npm)
3
0
Fatal crash points
MetricBeforeAfter
Steps to first ao spawn6+ (with manual edits)3 via npm, 4 from source
Interactive prompts in ao init130
Permission errors during setupFatal crashAuto-handled
Port conflicts on ao startFatal crashAuto-resolved
Adding a second projectManual YAML editingao add-project <path>
Dead CLI flags--smart shows "coming soon"Removed
"What's next" guidanceNone — user guessesEvery command prints the next step + directory
Dashboard for npm usersFatal crash (@composio/ao-web not published)Published + production entry point
Dashboard startup speed (npm)npx next start (slow global lookup)Direct node_modules/.bin/next binary
Error messages for missing packagesGeneric "Run: pnpm install" for all usersInstall-specific guidance (npm vs source)
CI reliabilityScripts exit 0 on npm link failureNon-interactive failures exit 1
Code duplicationdetectDefaultBranch copied in 2 filesSingle shared implementation

Backward Compatibility

Related Issues

#454 — Codex plugin stability improvements (spawned as a parallel agent session)
#456 — Dashboard shows orchestrator as "Exited" due to startup race condition

Test Plan