Policies, secrets, evidence

Secrets

A secret in Ship is anything that gives a system access to a tool, a vendor, or a tenant. The instinct that all secrets are the same is wrong, and the consequence of treating them the same is the workspace where one leak compromises everything. Ship divides secrets into three scopes—workspace, repo, and agent—because each has a different blast radius. The rule that binds them is simple: nothing sensitive ever ends up in a prompt or a committed config file. Secrets should never appear in conversation history, knowledge articles, routine prompts, or any place where they will be read into an agent's context. The moment a secret enters a prompt, every model the agent talks to has seen it, and the audit trail collapses.

Workspace integration secrets#

Credentials for third-party services bound at the workspace level live in the workspace secret store, encrypted at rest, and are referenced by integration id rather than copied around. These include Linear API keys, Notion tokens, Slack bot tokens, OpenTelemetry bearers, S3 access keys, and similar tools that the entire workspace might need to reach. Adding a new integration or rotating an existing credential is a settings change, not a code change. Members of the workspace cannot see the raw values of integration secrets; only workspace admins can perform rotation. Because these secrets unlock access that potentially affects every repo and agent in the workspace, they carry the highest blast radius and the strictest access model. The admin-only visibility rule exists because compromising a workspace integration secret means the attacker can touch every connected system—every Linear project, every Notion database, every Slack channel the workspace bot can reach.

Repo secrets#

Credentials scoped to a single connected repository are stored separately from workspace secrets because a repository's blast radius is narrower. A repo secret might be a deployment key that only one repo's CI needs, or a vendor token that only one codebase's workflows should use. Repo secrets are managed at the repository configuration page in the console and live outside the workspace secret store. When a Ship workflow on a repo needs a repo secret, the Ship GitHub App writes it to GitHub Actions secrets automatically at runtime; the secret itself never leaves the encrypted store until the moment it is needed in the workflow. This separation saves the workspace from the scenario where a compromised workspace-level credential puts every connected repository at risk. The principle is containment: if something goes wrong with one repository's authentication, the damage stays inside that repository.

Agent secrets#

Per-repo credentials that an agent itself uses at runtime—such as ANTHROPIC_API_KEY, OPENAI_API_KEY, CURSOR_API_KEY, and similar—live in a distinct secret store because the question "who rotated ANTHROPIC_API_KEY on this repo last week?" needs to have an answer. Agent secrets are audited per-repository, and the audit log records who set, rotated, or removed each agent secret and when. This granularity matters because an agent's API keys are typically the most frequently rotated and the most common point of accidental exposure. By surfacing agent secrets as a distinct category with per-repo tracking, Ship allows teams to answer security questions quickly and to enforce rotation policies without auditing entire workspace-level changes. An agent secret on repository A has no connection to the same secret on repository B; rotating one does not affect the other.

API tokens#

Tokens that authenticate into Ship—typically machine accounts for CI to call Ship's API, or for an external tool to read workspace state—are minted at Settings → API tokens with a name and a TTL. API tokens are not integration secrets; they are issued by Ship itself and serve as the credential that external systems use to authenticate API calls to Ship. Each API token can be revoked with a single click, and the audit log records both mint and revoke events. Treat the token as you would a password: never paste it into a chat, never log it to a file that might be checked in, and always store it securely in your environment or secret manager. If you suspect a token has been compromised, revoke it immediately; a new token can be minted in seconds.

The rule, restated#

Secrets do not belong in prompts. Secrets do not belong in .ship/config.yml. Secrets do not belong in a knowledge article, a routine prompt, an Inbox payload, a chat thread, or any place where they will be read into an agent's context. The reason is both practical and architectural: the book on policies before prompts argues in detail that when a secret enters a prompt, it is now visible to every model the agent converses with, the chain of custody is broken, and no audit trail can reconstruct where it went. In practice, the moment you type a secret into a text field that feeds an agent, you have compromised it. The only safe place for a secret is in a dedicated store that the agent can query without reading the raw value into memory.

Rotation#

The cheap habit: when an integration starts behaving oddly, rotate the secret on the provider first, then update Ship. The expensive habit: rotate inside Ship and discover the provider had already revoked the token. Rotation order matters because the disabled-on-provider state is the only thing that guarantees the old credential cannot be used. Replacing it inside Ship without disabling it on the provider leaves a window of overlap where an attacker can exploit the old value if they already have it. Always rotate on the provider first, then update the corresponding secret in Ship. Set calendar reminders for tokens that expire: Azure DevOps PATs, Atlassian API tokens, anything with a TTL. The audit log will show you when each secret was last rotated, but the calendar reminder is what keeps you from rotating too late.


The workspace secret store, the repo secret store, the agent secret store, and the API token store look like four mechanisms for the same thing. They are four mechanisms because they have four different blast radii and four different answers to the question "who should be able to see this, and when?" For a non-technical summary of what counts as a secret and why the distinction matters, see the appendix on what a secret is. For the question of where standing rules about secret handling live in your workflow, see the policies chapter.