Files
PaperClipAI/docs/deploy/environment-variables.md
T
Devin Foley e34ed9801b Let operators hide the Provider vaults and Proposals tabs (#12284)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Hosting operators (a managed cloud, an internal shared server) tune
the settings surface with `PAPERCLIP_HIDDEN_SETTINGS`, which today hides
whole pages
> - The Secrets page bundles four tabs, and two of them — Provider
vaults and Proposals — do not apply to deployments where the operator
provisions provider credentials itself
> - Hiding the whole Secrets page is too coarse: the Secrets and My
secrets tabs stay essential everywhere
> - This pull request adds per-tab visibility keys
(`company.secrets.vaults`, `company.secrets.proposals`) as a new
company-section registry group
> - The benefit is that any hosting operator can trim the Secrets page
to what fits their deployment, with self-hosted behavior unchanged by
default

## Linked Issues or Issue Description

No public issue exists; following the enhancement template:

**What existing behavior does this improve?**
`PAPERCLIP_HIDDEN_SETTINGS` can hide the whole Secrets page
(`company.secrets`) but not individual tabs. Operators of managed
deployments need to hide the Provider vaults and Proposals tabs while
keeping the rest of the page.

**Subsystem affected**
Settings visibility (`packages/shared/src/settings-visibility.ts`) and
the Secrets page UI (`ui/src/pages/Secrets.tsx`).

**Current behavior**
The Secrets page always renders all four tabs (Secrets, My secrets,
Provider vaults, Proposals), polls pending proposals for the badge, and
offers "manage vaults" affordances that jump to the vaults tab.

**Proposed behavior**
Two new registry keys, `company.secrets.vaults` and
`company.secrets.proposals`, hide the corresponding tab: the tab-bar
entry disappears, an active hidden tab snaps back to Secrets, the
manage-vaults affordances are suppressed, and the pending-proposals poll
stops. UI visibility only — the provider-config and proposal APIs stay
live for agents and integrations, matching the existing `company.*`
precedent. Nothing changes when the variable is unset.

**Reason and benefit**
Any hosting operator (a managed cloud, an internal shared server) can
trim the Secrets page to what fits their deployment — for example when
the operator provisions provider credentials itself, so the vault and
proposal flows do not apply — without losing the Secrets and My secrets
tabs, which stay essential everywhere.

**Breaking changes**
None. With `PAPERCLIP_HIDDEN_SETTINGS` unset (or set to existing keys
only) nothing changes; older app versions receiving the new keys ignore
them with a warning by design.

## What Changed

- `packages/shared/src/settings-visibility.ts`: new
`HIDEABLE_COMPANY_SECTIONS` group (`company.secrets.vaults`,
`company.secrets.proposals`), `HideableCompanySection` type,
`hidesCompanySection()` helper, wired into `HideableSettingKey` /
`HIDEABLE_SETTING_KEYS`, re-exported from the package index.
- `ui/src/pages/Secrets.tsx`: tab-bar filtering, hidden-tab snap-back
effect, gated pending-proposals query, conditional `onManageVaults` on
both the import button and dialog (the button's "AWS vault disabled —
manage" affordance renders nothing when vaults are hidden), hidden
`TabsContent` blocks.
- Docs: new bullet in `docs/deploy/environment-variables.md` under
"Hiding settings surfaces".
- Tests: registry membership/parse cases in
`settings-visibility.test.ts`; new render cases in
`Secrets.render.test.tsx` (hidden tabs absent + proposals poll skipped;
default render keeps both tabs and the poll).

## Verification

- `npx vitest run packages/shared/src/settings-visibility.test.ts
ui/src/pages/Secrets.render.test.tsx` — 43 tests passing.
- `pnpm --filter @paperclipai/shared typecheck` and `pnpm --filter
@paperclipai/ui typecheck` — clean.

## Risks

- Low. Nothing changes with `PAPERCLIP_HIDDEN_SETTINGS` unset (covered
by the default-render test). The keys are UI-visibility only, so
agent/integration API access is unaffected. Older app versions receiving
the new keys ignore them with a warning by design.

## Model Used

Claude (Anthropic), model id `claude-fable-5`, extended thinking,
agentic tool use via Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-27 11:28:15 -07:00

5.3 KiB

title, summary
title summary
Environment Variables Full environment variable reference

All environment variables that Paperclip uses for server configuration.

Server Configuration

Variable Default Description
PORT 3100 Server port
PAPERCLIP_BIND loopback Reachability preset: loopback, lan, tailnet, or custom
PAPERCLIP_BIND_HOST (unset) Required when PAPERCLIP_BIND=custom
HOST 127.0.0.1 Legacy host override; prefer PAPERCLIP_BIND for new setups
DATABASE_URL (embedded) PostgreSQL connection string
PAPERCLIP_HOME ~/.paperclip Base directory for all Paperclip data
PAPERCLIP_INSTANCE_ID default Instance identifier (for multiple local instances)
PAPERCLIP_DEPLOYMENT_MODE local_trusted Runtime mode override
PAPERCLIP_DEPLOYMENT_EXPOSURE private Exposure policy when deployment mode is authenticated
PAPERCLIP_API_URL (auto-derived) Paperclip API base URL. When set externally (e.g., via Kubernetes ConfigMap, load balancer, or reverse proxy), the server preserves the value instead of deriving it from the listen host and port. Useful for deployments where the public-facing URL differs from the local bind address.
PAPERCLIP_HIDDEN_SETTINGS (unset) Comma-separated settings surfaces to hide from the UI and floor at the API, for operators hosting Paperclip for others (managed cloud, internal shared server). See Hiding settings surfaces.

Hiding settings surfaces

PAPERCLIP_HIDDEN_SETTINGS takes keys from the registry in packages/shared/src/settings-visibility.ts:

  • Any instance settings page: instance.profile, instance.environments, instance.access, instance.heartbeats, instance.experimental, instance.plugins, instance.adapters — removed from navigation and routing (the General page is the settings root and stays visible). Hiding instance.access, instance.plugins, or instance.adapters also floors their management endpoints with 403 settings_operator_managed; hiding instance.experimental floors every experimental toggle write.
  • Any Instance → General section: instance.general.censorUsernameInLogs, instance.general.keyboardShortcuts, instance.general.backupRetention, instance.general.feedbackDataSharingPreference (each also rejects value-changing writes via PATCH /api/instance/settings/general), plus the UI-only instance.general.deploymentStatus and instance.general.signOut.
  • Any experimental toggle: instance.experimental.<flagKey> (e.g. instance.experimental.enableSmokeLab) — the card disappears and value-changing writes are rejected.
  • Any top-level company settings page: company.members, company.invites, company.secrets, company.export, company.import — removed from the settings sidebar, tab bar, and routing (the company General page is the settings root and stays visible). These are UI-visibility keys: the membership, invite, secret, and export APIs stay live for agents and integrations. company.import is the exception — hiding it also floors every company-import route with 403 settings_operator_managed. On cloud-managed instances import is floored unconditionally with 403 cloud_managed, independent of this variable.
  • A single tab of the Secrets page: company.secrets.vaults (Provider vaults) and company.secrets.proposals (Proposals) — the tab disappears while the rest of the page stays up. UI-visibility only; the secret provider-config and proposal APIs stay live for agents and integrations.

Unknown keys are logged and ignored, so one list can be rolled across a fleet of mixed app versions. With the variable unset nothing is hidden and behavior is identical to earlier releases. Hiding a toggle does not change its value; pair hiding with the desired default where it matters.

Secrets

Variable Default Description
PAPERCLIP_SECRETS_MASTER_KEY (from file) 32-byte encryption key (base64/hex/raw)
PAPERCLIP_SECRETS_MASTER_KEY_FILE ~/.paperclip/.../secrets/master.key Path to key file
PAPERCLIP_SECRETS_STRICT_MODE false Require secret refs for sensitive env vars

Agent Runtime (Injected into agent processes)

These are set automatically by the server when invoking agents:

Variable Description
PAPERCLIP_AGENT_ID Agent's unique ID
PAPERCLIP_COMPANY_ID Company ID
PAPERCLIP_API_URL Paperclip API base URL (inherits the server-level value; see Server Configuration above)
PAPERCLIP_API_KEY Short-lived JWT for API auth
PAPERCLIP_RUN_ID Current heartbeat run ID
PAPERCLIP_TASK_ID Issue that triggered this wake
PAPERCLIP_WAKE_REASON Wake trigger reason
PAPERCLIP_WAKE_COMMENT_ID Comment that triggered this wake
PAPERCLIP_APPROVAL_ID Resolved approval ID
PAPERCLIP_APPROVAL_STATUS Approval decision
PAPERCLIP_LINKED_ISSUE_IDS Comma-separated linked issue IDs

LLM Provider Keys (for adapters)

Variable Description
ANTHROPIC_API_KEY Anthropic API key (for Claude Code adapter)
OPENAI_API_KEY OpenAI API key (for Codex adapter)