Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2c88dcd
config: pickApiUrl seam with a runtime --api-url override above INSTA…
jwfing Sep 17, 2026
19346eb
postgres: rename db.ts, every verb takes a trailing [service] instead…
jwfing Sep 17, 2026
2c87c8b
managed databases: type-generalized limits/volume/always-on, status o…
jwfing Sep 17, 2026
81c0f43
compute scale + storage set-access replace the services scale/set-acc…
jwfing Sep 17, 2026
52744de
domain attach covers bought and bring-your-own hostnames; check/detac…
jwfing Sep 17, 2026
5601f70
domain: conflict hint names the new attach path
jwfing Sep 17, 2026
7dd53f5
index: noun-first command tree (24 top-level), per-resource logs/metr…
jwfing Sep 17, 2026
54e65bf
index: --region hints name config regions; surface test timeouts
jwfing Sep 17, 2026
13dcc03
hints, next-action commands and telemetry redaction follow the new co…
jwfing Sep 17, 2026
5c982ae
tests: keep the db.query literal-dot escape; comment wording follows …
jwfing Sep 17, 2026
8f2bb7a
docs: command table, agent-setup probe in install.sh, command-archite…
jwfing Sep 17, 2026
3633c73
install.sh: probe the root help for the agent group; README names onl…
jwfing Sep 17, 2026
b32d648
fix: retired billing upgrade fails loudly; autoupdate never persists …
jwfing Sep 17, 2026
fc91e07
setup agent stays as a hidden alias of agent setup (the console one-l…
jwfing Sep 18, 2026
0e86d0e
managed databases: volume offers no --delete (the platform refuses it…
jwfing Sep 18, 2026
671abf6
Merge branch 'main' into feat/command-reorg
jwfing Sep 18, 2026
663391c
review: address PR #252 findings (persisted --api-url, domain detach …
jwfing Sep 18, 2026
0a7417f
logout acts on the stored session, not on a runtime --api-url
jwfing Sep 18, 2026
27a3f0f
deploy: the build-log hint names `insta build logs`
jwfing Sep 18, 2026
3383cf4
review: persist guard test, detach fallback, volume/logout wording
jwfing Sep 18, 2026
b8400ad
Merge remote-tracking branch 'origin/main' into feat/command-reorg
jwfing Sep 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions .claude/skills/developing-insta-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ npx tsx src/index.ts --help # run the CLI from source
| `index.ts` | commander program — registers every command |
| `api.ts` | typed platform-API client (auth headers, token refresh, error mapping) |
| `config.ts` | global `~/.insta/config.json` (apiUrl + tokens + user) · project `./.insta/project.json` (projectId / orgId / current branch) · machine-local `./.insta/link-plane.json` (the control plane the link was made on; a foreign link fails closed in `requireProject`) |
| `commands/` | one file per command group: `auth` `org` `project` `services` `branch` `secrets` `build` `deploy` `compute` `upgrade` `metrics` (+`logs`) `billing` `govern` (policy/approvals) `manifest` `observe` |
| `observe/` | local `insta observe` hook — `scanner.ts` (AWS/GitHub/Stripe/LLM/DB cred detection), `hook.ts`, `install.ts`, `report.ts` (→ platform event ingest) |
| `commands/` | one file per command group: `auth` `org` `project` `branch` `services` (the `service` group) `secrets` `domain` `compute` (+ BYO domain functions, type-generalized limits/volume/always-on) `postgres` `managed-db` (redis/mysql/mongodb status) `db-query` `storage` `build` `deploy` `run` `template` `billing` `metrics` (+`logs`, `usage`) `govern` (approvals/events) `agent-policy` `observe` `manifest` `setup` `mcp` `regions` `env` `feedback` `upgrade` |
| `observe/` | local `insta agent observe` hook — `scanner.ts` (AWS/GitHub/Stripe/LLM/DB cred detection), `hook.ts`, `install.ts`, `report.ts` (→ platform event ingest) |
| `flyctl-build.ts` | source-directory deploy build glue (Fly build context) |
| `nixpacks.ts` | nixpacks glue for `insta build` — plan detection + Dockerfile generation (no Docker daemon) |
| `ensure-skills.ts` | installs/refreshes the agent skills into the user's project |
Expand All @@ -37,6 +37,40 @@ npx tsx src/index.ts --help # run the CLI from source
`skills/` submodule) — that reference doc is how agents learn the CLI surface, so a new or
renamed command/flag is only half-done until it's updated there, in the same change set.

## Command architecture (read before adding or moving a command)

The tree in `src/index.ts` follows five rules (design: superproject
`docs/superpowers/specs/2026-09-17-cli-command-reorg-design.md`). `test/help-surface.test.ts`
pins the visible top level; changing it is a design decision, not a code change.

1. **Level 1 is a resource (noun, singular).** The only verbs at level 1 are `login`, `logout`,
`status`, `build`, `deploy`, `run`, `feedback`, `upgrade`. Nothing else joins without a design note.
2. **Level 2 is a verb on that resource.** A third level makes level 2 a noun again
(`domain records add`, `agent policy set`).
3. **One capability, one path.** Before adding a command, grep `src/commands/` for the platform
endpoint it calls. If another command already calls it, add a flag or mode there instead.
4. **Same shape for the same thing.** `compute|postgres|redis|mysql|mongodb <verb> [service]` —
trailing optional positional, sole/default service when omitted (`resolveSoleService`) — except
managed-database `query`, where the service is required and LEADS (`query <service> [args…]`),
because a trailing optional service cannot be told apart from the query argv (`insta redis query
GET key`) without a `--` separator like `compute exec` uses; the design's §8 records it as
deferred, and `test/help-surface.test.ts` pins it. `storage <verb> --service <name>`; org-scoped
verbs take `--org <id>`. A new verb copies its group's shape; a new group copies the closest
existing group.
5. **Renames are hard cutovers.** No hidden aliases, with two permanent exceptions: `services|svc` → `service`, and hidden `setup agent` → `agent setup` (the console one-liner is printed in too many places to cut over).
A rename changes, in the same change set: `skills/insta/cli-reference.md`, `e2e/`, console copy
in `frontend/`, MCP copy, and platform error strings that spell the path — and it ships in the
order the design's §9 gives (docs/copy merge right after the CLI release, never before).

Where things go: settings (limits/volume/always-on/scale) live under the service type;
`logs`/`metrics` live under the service type via `addObservability()` in `index.ts`; anything
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
about this machine's agents or the project's agent governance lives under `agent`; anything about
this machine's CLI configuration lives under `config`. `--api-url` is injected on every command by
`addApiUrlEverywhere()`, with two deliberate exceptions: the root and `login` declare the option
themselves (`login` is the one command that may persist the URL it is given), and `compute exec` is
skipped because its argv is split before commander ever sees it — there, pass the flag at the root
(`insta --api-url X compute exec …`). Never declare `--api-url` on a new command by hand.

## Getting a PR merged (main is protected — this exact flow, no other works)

1. Branch from `origin/main`: `feat/*` or `fix/*`. PRs target `main`. **Squash merge.**
Expand Down Expand Up @@ -70,6 +104,7 @@ npx tsx src/index.ts --help # run the CLI from source
| `npx insta@latest` behind the GH release | `publish-npm` job failed (OIDC trust/config?) — see step 4 |
| `'C:\Program' is not recognized` from a spawned tool (win CI only) | `resolveSpawnable`'s cmd.exe hop strips the quotes around a spaced executable path (`C:\Program Files\…`). It exists for npm-installed `.cmd` shims — a real `.exe` (git, …) must be spawned directly, which finds it through PATHEXT anyway |
| CLI hits the wrong server in tests | Persisted `~/.insta/config.json` apiUrl; set `INSTA_API_URL` (≥0.0.7) or move the config aside |
| `insta --api-url X compute exec …` works but `insta compute exec --api-url X …` says unknown option | exec's argv is split before commander (`splitExecArgs`); pass `--api-url` at the root for exec |

## agents.instacloud.com

Expand Down
57 changes: 28 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ version-pinned `npm install -g` fallback to run yourself). E2e-validated on macO
and Windows (PowerShell + cmd):

```bash
npx -y insta@latest setup agent
npx -y insta@latest agent setup
```

`insta setup agent` is still accepted as a hidden alias, so older instructions keep working.

This command means **production** (CLI ≥ 0.0.38): if the machine was previously switched to
staging it switches back — announced, session dropped, like `insta env use prod`. Staging is
its own explicit command, which also persists the choice:

```bash
npx -y insta@latest setup agent --env staging
npx -y insta@latest agent setup --env staging
```

On macOS/Linux without Node, the native-binary installer puts the `insta` CLI on PATH (the
Expand All @@ -56,7 +58,7 @@ curl -fsSL agents.instacloud.com | sh

Pin a version with `INSTA_VERSION=v0.0.22`; change the install directory with
`INSTA_INSTALL_DIR`. While the CLI is pre-1.0 it updates itself on new releases. Turn that
off with `insta autoupdate off`.
off with `insta config autoupdate off`.

## Quickstart

Expand All @@ -72,7 +74,7 @@ insta deploy .

`project create` makes an empty project and links the current directory. Services are
opt-in, so you add only what you need. `secrets` writes the current branch's user-defined
secrets to `./.env` (the postgres connection string is read with `insta db url`). `deploy .`
secrets to `./.env` (the postgres connection string is read with `insta postgres url`). `deploy .`
builds the directory remotely and ships it to the branch's compute
service, with no local Docker. Whether it needs a `Dockerfile` depends on where the
service runs: on insta-compute it is optional, and a directory without one is built
Expand Down Expand Up @@ -119,7 +121,7 @@ the two branches diverge independently. A project is capped at 10 branches.
only. Provider-minted service credentials (`DATABASE_URL`, `BUCKET_NAME`,
`AWS_ACCESS_KEY_ID`, …) are not in that bundle — they reach compute through explicit
`insta secrets bind` rules, and the postgres connection string is read directly with
`insta db url` (or `insta db connect` for a psql session).
`insta postgres url` (or `insta postgres connect` for a psql session).

Secrets can be scoped per compute service, so several services may each define the same name — and
a flat bundle cannot carry two values for one name. Such a name is **withheld** from the bundle and
Expand All @@ -133,8 +135,8 @@ it as `insta run --service compute/<name>` to inject exactly what that one servi

Agent requests are governed by the project's `agent-policy`; human requests use normal RBAC.
Where the agent policy says `approve`, the command stops and prints an approval id for a human
admin to grant with `insta approvals approve <id>`. The agent then retries the unchanged request.
Run `insta --agent agent-policy get --json` for stored overrides, `defaultRules`, `effectiveRules`,
admin to grant with `insta agent approvals approve <id>`. The agent then retries the unchanged request.
Run `insta --agent agent policy get --json` for stored overrides, `defaultRules`, `effectiveRules`,
`bootstrapRules` and `ruleNotes`. Rules distinguish no affected branches (`project`), unprotected
branches and protected branches. They describe policy, not authorization: RBAC, session checks,
actual affected resources and compound actions still apply. An empty override object does not
Expand All @@ -143,8 +145,8 @@ mean rules are unavailable. Text output also lists effective rules. The old `pol

### Agents get the same surface

`insta manifest` prints an agent-legible view of every branch and its URLs. `insta setup
agent` installs the InstaCloud skill and registers the remote MCP server for the coding
`insta agent manifest` prints an agent-legible view of every branch and its URLs. `insta agent
setup` installs the InstaCloud skill and registers the remote MCP server for the coding
agents on the machine — and, when running from the npx cache with no durable `insta` on
PATH, first installs the CLI itself globally.

Expand Down Expand Up @@ -211,29 +213,26 @@ build never reaches a production installer.
| Command | What it covers |
|---|---|
| `insta login` · `logout` · `status` | Browser sign-in (default), `--email` + password, or `--oauth github\|google`; `status` shows the environment, login and linked project/branch |
| `insta env` | `show` · `use <prod\|staging>` |
| `insta setup` | `agent` — install the CLI (if missing), the skill, and MCP for every coding agent; targets prod, `--env staging` for staging |
| `insta mcp` | `install` — register the remote MCP server only |
| `insta org` | `list` · `create` (one free org per user) |
| `insta project` | `create` · `list` · `link` · `delete` |
| `insta branch` | `create` · `list` · `switch` · `delete` · `merge` |
| `insta services` | `add` · `list` · `remove` · `rename` · `set-access` · `scale` · `upgrade` · `secrets` |
| `insta secrets` | Write `.env`, plus `list` · `set` · `unset` · `tree` |
| `insta service` (`services`, `svc`) | `add` · `list` · `remove` · `rename` |
| `insta secrets` | Write `.env`, plus `list` · `set` · `unset` · `bind` · `unbind` · `bindings` · `sources` · `tree` |
| `insta domain` | Bought or bring-your-own: `attach` · `check` · `detach`; buy through InstaCloud: `search` · `buy` · `list` · `status` · `records …` |
| `insta compute` | `start` · `stop` · `suspend` · `restart` · `status` · `scale` · `limits` · `volume` · `always-on` · `exec` · `ssh` · `repo` · `connect-repo` · `watch-paths` · `disconnect-repo` · `logs` · `metrics` |
| `insta postgres` | `url` (print the DSN) · `connect` (psql) · `stats` · `limits` · `volume` · `always-on` · `logs` · `metrics` — every verb takes `[service]` |
| `insta redis` · `mysql` · `mongodb` | `query` · `status` · `limits` · `volume` · `always-on` · `logs` · `metrics` |
| `insta storage` | `list` · `get` · `delete` · `set-access` |
| `insta build [dir]` · `deploy [dir]` | Verify a source dir would build; deploy a source directory (built remotely) or `--image <url>`. `insta build logs <id>` reads source-build output: `--source archive` (default) uses the deploy operation ID, `--source github` uses a GitHub build ID; `--follow` watches output, `--json` returns one snapshot |
| `insta run <cmd>` | Run a command with the branch bundle injected, nothing written to disk |
| `insta deploy [dir]` | Deploy a source directory (built remotely) or `--image <url>` |
| `insta compute` | `start` · `stop` · `suspend` · `status` · `set-domain` · `check-domain` · `remove-domain` |
| `insta domain` | Buy a domain through InstaCloud: `search` · `buy` · `attach` · `list` · `status` |
| `insta db` | `url` (print the postgres DSN) · `connect` (psql session) · `limits` · `stats` · `always-on` · `volume` |
| `insta regions` | Regions available for postgres and compute |
| `insta manifest` | Agent-legible view of every branch and its URLs |
| `insta build-logs <id>` | Read source-build output; `--source archive` (default) uses the deploy operation ID, `--source github` uses a GitHub build ID; `--follow` watches output, `--json` returns one snapshot |
| `insta metrics` · `logs` · `events` | Service metrics; runtime logs (`--deploy` for deploy events); audit timeline |
| `insta usage` · `billing` | Usage by billing dimension; `billing upgrade` · `billing portal` |
| `insta approvals` | `list` · `approve` · `deny` |
| `insta agent-policy` | `get` · `set <mode>` · `protect-branch` · `unprotect-branch` · `rule set <action> <decision>` · `revoke-sessions` |
| `insta observe` | `install` · `uninstall` · `report` · `sync` — local credential audit |
| `insta template` | `list` · `info` · `deploy` |
| `insta billing` | Current cycle overview; `subscribe <tier>` · `portal` · `usage` |
| `insta agent` | `setup` (this machine's coding agents) · `manifest` · `policy …` · `approvals …` · `observe …` · `events` |
| `insta config` | `install-mcp` · `regions` · `autoupdate` |
| `insta feedback` | Report an InstaCloud-side hurdle (bug / feature-request / friction) to the team — never for the app you are building; works logged-out |
| `insta upgrade` · `autoupdate` | Update the CLI; show or set auto-update |
| `insta upgrade` | Update the CLI |

Every command accepts `--api-url <url>` for this invocation only (internal debugging); for `compute exec`, place it before `compute`. `insta --help` documents it.

## Configuration

Expand All @@ -256,10 +255,10 @@ build never reaches a production installer.
## Agent skills

The `insta` skill and its task guides live in
[InsForge/instacloud-skills](https://github.com/InsForge/instacloud-skills). `insta setup agent`
[InsForge/instacloud-skills](https://github.com/InsForge/instacloud-skills). `insta agent setup`
installs it user-globally for every coding agent on the machine. `insta project create` and
`insta project link` additionally install the stack skills (Tigris, Better Auth) into the
project, along with the `insta observe` credential-audit hook. Postgres needs no stack
project, along with the `insta agent observe` credential-audit hook. Postgres needs no stack
skill — it's plain Postgres, reached directly via `DATABASE_URL`.

## Contributing
Expand Down
13 changes: 8 additions & 5 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# (equivalent to piping this script with: sh -s -- --agents; add -y for a hard non-interactive run)
#
# Flags:
# --agents after installing, run `insta setup agent` (skills for Claude Code/Codex/Cursor/…)
# --agents after installing, run `insta setup agent` (alias of `insta agent setup`) — installing skills for Claude Code/Codex/Cursor/…
# -y non-interactive
# --staging target the staging deployment (shorthand for --env staging)
# --env <name> target a named deployment: prod (default) | staging
Expand Down Expand Up @@ -201,7 +201,7 @@ if [ "$ON_PATH" != "1" ]; then
fi

# ---- environment (--staging / --env) ----
# MUST run before `setup agent`: that step registers the MCP server, and it derives the MCP host and
# MUST run before `agent setup` (`setup agent` on older CLIs): that step registers the MCP server, and it derives the MCP host and
# registration name from the persisted environment. Switching afterwards would leave the machine's
# agents pointed at production's MCP server while the CLI talked to staging.
if [ -n "$ENV_NAME" ]; then
Expand All @@ -211,7 +211,7 @@ if [ -n "$ENV_NAME" ]; then
# install is still pointed at PRODUCTION. Carrying on would be the worst outcome: the canonical
# usage is `curl … | sh && insta project create`, often run unattended by an agent, which would
# then provision real production infrastructure believing it was staging. Exiting here also
# stops `setup agent` from wiring this machine's agents to the wrong environment.
# stops `agent setup` (`setup agent` on older CLIs) from wiring this machine's agents to the wrong environment.
echo "error: could not select environment '$ENV_NAME' — this install is still pointed at PRODUCTION." >&2
echo " The installed CLI ($("$INSTALL_DIR/$BIN" --version 2>/dev/null | tail -1)) may predate \`insta env\` (needs >= 0.0.23)." >&2
echo " Upgrade, then retry: insta upgrade && insta env use $ENV_NAME" >&2
Expand All @@ -223,8 +223,8 @@ fi
# ---- agent setup (--agents) ----
if [ "$AGENTS" = "1" ]; then
echo
# `insta setup agent` prints its own "setting up coding-agent skills …" line + clean summary.
# CLI >= 0.0.38: bare `setup agent` FORCES prod (switching the machine if needed), so a staging
# `insta agent setup` (`setup agent` on older CLIs) prints its own "setting up coding-agent skills …" line + clean summary.
# CLI >= 0.0.38: bare `agent setup` (`setup agent` on older CLIs) FORCES prod (switching the machine if needed), so a staging
# install must pass the environment explicitly. The persisted env already matches (env use above),
# so --env is a no-op switch there — it just stops setup from "correcting" the machine to prod.
# Older CLIs (a pinned INSTA_VERSION) reject the flag; ONLY that exact case (commander's
Expand All @@ -240,6 +240,9 @@ if [ "$AGENTS" = "1" ]; then
YFLAG=""
[ "$YES" = "1" ] && YFLAG="-y"
SETUP_ERR="${TMPDIR:-/tmp}/insta-setup-err.$$"
# `setup agent` is the permanent compatibility alias of `insta agent setup` (canonical since the
# command re-organization). It works on every release, which is exactly what a script fetched from
# `main` and run against whatever binary is current needs — do not "modernize" this call.
if "$INSTALL_DIR/$BIN" setup agent $YFLAG $SETUP_ENV_ARGS 2>"$SETUP_ERR"; then
cat "$SETUP_ERR" >&2
else
Expand Down
4 changes: 2 additions & 2 deletions src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function canonicalTarget(path: string): string {
const url = new URL(path, 'https://platform.invalid')
return url.pathname + url.search
}
const guidance = 'agent session missing, expired, or for another project/environment — run `insta setup agent`'
const guidance = 'agent session missing, expired, or for another project/environment — run `insta agent setup`'

export async function issueAgentSession(api: SessionApi, projectId?: string): Promise<Session> {
const pair = generateKeyPairSync('ed25519')
Expand All @@ -35,7 +35,7 @@ export async function issueAgentSession(api: SessionApi, projectId?: string): Pr
export async function saveAgentSession(session: Session, cwd = process.cwd()): Promise<void> {
const root = await findProjectRoot(cwd) ?? cwd
const rel = '.insta/agent-session.json'
if (alreadyTracked(root, [rel]).length) throw new Error('agent-session.json is tracked by Git; untrack it before running insta setup agent')
if (alreadyTracked(root, [rel]).length) throw new Error('agent-session.json is tracked by Git; untrack it before running insta agent setup')
ensureGitignore(root, [rel], '# Local agent credentials')
const dir = join(root, '.insta')
await mkdir(dir, { recursive: true })
Expand Down
Loading
Loading