Skip to main content

Project context

A command has to know where it is operating: which organization, which project, which environment, which endpoint. Answering that per developer — a flag here, an exported variable there, a profile someone configured months ago — is how two people run the same command and get different results.

vagary.json is the answer you commit. It is a project declaration: non-secret, checked in, and read by every command.

Create one​

vagaris project init --organization acme --project-name voice-support --environment production
{
"$schema": "https://docs.vagaris.org/schemas/project-manifest.v1.json",
"version": 1,
"organization": "acme",
"project": "voice-support",
"environment": "production"
}

Commit it. A teammate who clones the repository resolves the same context with no setup, and CI does too. Authentication stays individual — the file never carries a credential.

warning

A manifest can never contain a secret. There is no apiKey field, and unknown keys are refused outright rather than ignored, so one cannot be added by accident. The file is meant to be committed, and a credential in git is compromised the moment it lands. Credentials come from your environment, your stored login, or a flag.

Precedence​

Six layers, highest first:

LayerExample
Explicit flag--company-id acme
EnvironmentVAGARY_ORGANIZATION=acme
Project manifestvagary.json
Named profilevagaris context use enterprise-mumbai
User/global config~/.paperclip/config.json
Derived defaultinferred from local config

Every field resolves independently. This matters more than it looks. Given a manifest naming an organization and a project, plus an environment override in CI:

VAGARY_ENVIRONMENT=staging vagaris feature list
organization = acme          [vagary.json]
project = voice-support [vagary.json]
environment = staging [environment]

The override changes the environment and nothing else. Your organization does not disappear because a higher-precedence layer spoke about a different field — which is exactly what a repository-wide manifest plus per-job overrides needs in order to work.

See why​

vagaris context show --explain
  Organization:  acme                        [vagary.json]
Project: voice-support [vagary.json]
Environment: staging [environment]
Profile: enterprise-mumbai [profile]
Region: — [not set]
API endpoint: https://vagaris.acme.com [profile]
Credential: present [not displayed]

Project manifest: /Users/you/acme-web/vagary.json

Every line names the layer that supplied it. You should never have to read source code to answer "why is this targeting that organization?".

The credential row reports only whether one is present — never its value, its name, or its length. A value printed to a terminal reaches scrollback, screen shares and CI logs.

A broken manifest fails loudly​

A manifest that exists but does not parse is not treated as no manifest:

  The project manifest at /Users/you/acme-web/vagary.json was NOT applied — it does not
match the schema — organization: Required
Every value above came from a lower layer. This is not the state the file describes.

Silently falling back would leave a project running on whatever a profile happened to say, while a file sat in git looking correct. A typo must be visible.

Fields​

FieldMeaning
versionSchema version. Required — an unknown version is refused, never reinterpreted.
organizationThe organization this project belongs to.
projectThe project within it.
environmentThe environment this checkout targets.
capabilitiesCapability/binding references — pointers into the registry, not entitlement state.
profileA named profile the team standardises on.
regionPlacement preference.
endpointAn API endpoint override.
metadataName and description, for humans. Never used for routing.
note

endpoint is an override, not the foundation. A project is Organization → Project → Environment, and the endpoint is normally derived from that. Setting only an endpoint describes a URL rather than a project, and context show --explain will tell you so. It stays supported for self-hosted, on-prem, local development and private enterprise deployments, where it is genuinely the right answer.

Where the manifest is found​

Searched from the working directory upward, like .git — so a command run deep inside a monorepo package resolves the same context as one run at the root. vagary.json is checked before .vagary.json.

Environment variables​

Canonical names are read first, with the historical PAPERCLIP_* names kept working:

FieldCanonicalAlso read
organizationVAGARY_ORGANIZATIONPAPERCLIP_COMPANY_ID
projectVAGARY_PROJECTPAPERCLIP_PROJECT
environmentVAGARY_ENVIRONMENTPAPERCLIP_ENVIRONMENT
profileVAGARY_PROFILEPAPERCLIP_PROFILE
regionVAGARY_REGIONPAPERCLIP_REGION
endpointVAGARY_ENDPOINTPAPERCLIP_API_URL

An environment that sets both gets the canonical value. One that sets only the older name keeps working unchanged. A variable exported empty counts as unset at every layer, so a stray export VAGARY_ORGANIZATION= in a shell profile does not silently outrank your manifest.