Agent Patterns
How to run Claude Code, Cursor, and Codex against PromptShip — prompt shape, file conventions, and permissions that make agents reliable.
This is the counterpart to the MCP reference. It's not "what the tools do" — that's already documented. It's "what a prompt has to look like, what CLAUDE.md has to say, and which permissions have to be scoped for an agent to ship to production without supervision."
Three patterns, in the order you'll need them:
- Preview environments per deploy — ship to a preview first, verify, then promote.
- Structuring CLAUDE.md for PromptShip — where Claude Code reads team conventions.
- Safe permissions for autonomous runs — what to lock down before walking away.
Preview environments per deploy
Every app on PromptShip can have multiple environments. Treat one of them (prod) as the user-facing target and the rest (preview, staging, branch-scoped names) as the sandbox an agent ships to first. The agent deploys the branch to preview, hits the preview URL to verify the feature works, and only then promotes to prod. If anything goes wrong, the blast radius is the preview env — users see nothing.
The prompt shape
Tell the agent to use the preview branch as a staging step, not the final target. A prompt that reliably produces this shape:
Your goal is to ship <feature> to production.
Workflow:
1. Create a branch named feature/<slug>.
2. Implement the change. Run the tests locally (pytest, vitest, etc.).
3. Commit and push.
4. Call deploy_app with environment="preview" branch="feature/<slug>".
5. Poll get_deploy_status until status is "succeeded".
6. Hit the preview URL returned by get_app. Verify <concrete acceptance criteria>.
7. Only if verification passes, call deploy_app with environment="prod"
branch="feature/<slug>".
8. Open a PR to main.
If any step fails, read get_logs, patch the code, and retry from step 3.
Do not skip step 6. Do not call deploy_app with environment="prod" before preview
has succeeded.
Why this shape
Each instruction corresponds to a guardrail the platform enforces. The deploy_app → get_deploy_status loop is the only way the agent learns whether the build passed. The get_logs call is the only way it recovers from a failed deploy without a human. Skipping either step means the agent ships to prod blind.
What this implies for prompts. Always name the environment explicitly in the prompt. "Deploy my app" without an env name is ambiguous — an agent may default to prod. "Deploy to preview first, verify, then promote" is the phrase that keeps the guardrail.
Structuring CLAUDE.md for PromptShip
Claude Code reads CLAUDE.md at repo root as project context on every session. Treat it as the place where you encode the team's deploy conventions, not just coding style. A good PromptShip-aware CLAUDE.md has three sections: what the deploy surface is, which MCP tools are safe by default, and which require human approval.
Starter template
Drop this at the top of your repo's CLAUDE.md and edit the app names and environment list to match:
# Deployment
This project is deployed on PromptShip.
- App name: <my-app>
- Environments: prod (live), preview (sandbox for branch verification)
- Deploy tool: MCP via `promptship` server
## Safe-by-default MCP tools
Use these freely without asking:
- get_app, list_apps, get_app_config, get_deploy_status, get_logs
- get_db_attach_status (polling an in-flight attach)
- list_secrets (key names only; values are never returned)
- deploy_app with environment="preview"
- attach_postgres / attach_valkey / attach_clickhouse with tier="pg-1" / "valkey-1" / "ch-1" in non-prod environments only (async — follow each with get_db_attach_status until status is "succeeded")
- query_postgres_readonly / query_valkey_readonly / query_clickhouse_readonly (engine-enforced readonly analysis; no approval)
## Tools that require explicit human approval
Ask before calling any of these:
- deploy_app with environment="prod"
- delete_app, delete_environment
- detach_postgres / detach_valkey / detach_clickhouse (data retention is 1 hour, not forever)
- reset_postgres / reset_valkey / reset_clickhouse (wipes data)
- change_app_tier, change_*_tier (affects billing at end of early access)
- set_secret / delete_secret (credential changes)
- change_team_plan, invite_member, remove_member, update_member_role
- set_domain, remove_domain
- query_postgres / query_valkey / query_clickhouse in production (write-capable; follow the returned approval next_step)
## Workflow conventions
- Branches: feature/<ticket-id>-<slug> (e.g. feature/ENG-421-oauth-refresh or feature/issue-142-oauth-refresh)
- Every feature ships to preview before prod. Verify the preview URL before promoting.
- If a deploy fails, read get_logs before patching — don't guess.
- Leave a comment on the ticket when you promote to prod.
What this implies for prompts. With CLAUDE.md in place, your per-task prompts get dramatically shorter — "ship <feature>, follow the workflow in CLAUDE.md" is enough. Without it, every prompt has to re-state the safety conventions, which agents forget under pressure.
Safe permissions for autonomous runs
When an agent runs unattended, the guardrails that matter aren't in the prompt — they're in the token. PromptShip has three levels: team roles (owner / admin / member), app permissions (member / admin, app-wide or scoped to named environments), and the token's own environment scope. Combine them so a stuck agent can't do lasting damage.
Create a scoped agent token
Use create_token to mint a token specifically for the agent, not your personal token. A per-agent token is named, expiring (30 days by default, 90 max), revocable on its own — and every action it takes is recorded under its name:
> promptship tokens create claude-code-nightly --scope env_type:preview --expires-in-days 30
Token: ps_<redacted>
Expires: 2026-09-10T12:00:00+00:00
Store this token securely — it will not be shown again.
--scope env_type:preview is the token that cannot touch production at all: it may act only on non-prod environments, present and future. --scope env:dev pins it to one named environment instead. A trailing @<app> confines a clause to one project — --scope env:dev@billing, or --scope @billing for all of billing's environments — so an agent minted for one app can neither act on nor even see another. The flag is required — full access has to be asked for with --scope app, so no token is ever unscoped because someone forgot. The restriction is enforced by the platform on every call, not by the prompt — a scoped token does not even see the apps or environments it is not scoped to.
promptship login mints this machine's own CLI token the same way: it asks what that token may reach (non-prod only, named environments, or everything), and takes --scope for scripted installs.
Then narrow what that token can touch. Agent tokens should be issued to a service account user who is a member (not admin) of the team, with admin access only on the specific apps — or the specific environments — the agent is responsible for (promptship permission grant <app> <user> --statement admin:env:dev --statement member:env:prod — one call states the whole grant). Apps the agent has no business seeing can be hidden entirely with promptship apps visibility <app> --restricted. That means:
- Can: deploy, attach DBs, set secrets, query the app's own databases — in the environments it is scoped to.
- Cannot: touch prod (when scoped to preview), delete apps, change build config, change team plans, invite new members, mint or revoke tokens, touch other apps on the team.
Read back what the agent did
Every write is attributed to the acting token, so one call answers "everything this agent did":
> promptship audit --token claude-code-nightly
> promptship audit --task-id nightly-2026-08-11 # every attempt at one task
Credential lifecycle is in there as well: token.created when a token is minted (from the CLI, the dashboard, or the MCP consent screen), token.revoked when one is destroyed, and github.connected / github.disconnected — each recording the identity's name, scope and expiry, never the token value.
Agents can read it too (list_agent_actions) — useful for a wrap-up summary or for a manager agent verifying its sub-agents. MCP tools accept optional task_id and agent_tag arguments that tag the entries a session writes; from a shell, set PROMPTSHIP_TASK_ID and PROMPTSHIP_AGENT_TAG and every CLI call joins the same trace. They group the trace and never grant anything.
Explicit lockdown list
For unattended runs (cron-triggered, long-running background agents), disable these tools at the MCP layer entirely. In Claude Code, this is a settings.json disabledTools entry. In Cursor/Codex, use the equivalent MCP config:
delete_app,delete_environment— irreversible resource deletion.change_team_plan,invite_member,remove_member,update_member_role— team structure.reset_postgres,reset_valkey,reset_clickhouse— data wipes.detach_postgres,detach_valkey,detach_clickhouse— 7-day data retention, but still dangerous if fired by mistake.set_domain,remove_domain— DNS / TLS impact.
Supervised sessions (you're watching the IDE) can keep these enabled with "ask before calling" CLAUDE.md rules. Unattended sessions should remove them from the tool surface entirely — Claude can't call a tool it can't see.
What this implies for prompts. Don't rely on prompts to enforce safety. Prompts are advisory; token scope and disabled-tool lists are the actual guardrail. If a task genuinely needs a dangerous tool (e.g., change_app_tier for a scheduled scale-up), mint a separate one-task token with exactly that permission and revoke it after.