ProofStack has two explicit local profiles. The default in-memory profile is dependency-free and disposable. The PostgreSQL profile persists evidence across API and database restarts and exercises the same migrations, row-level tenant isolation, and least-privilege role boundaries used by the durable adapter.
Both profiles default to development authentication on an explicit loopback listener. The durable profile can also exercise the experimental workload API-key path. The OIDC browser backend is implemented, but exercising it requires a configured provider and an HTTPS endpoint in front of the API; the repository does not yet ship that TLS proxy as a production deployment artifact.
- Node.js 24 or newer.
.nvmrcpins the exact CI baseline, currently 24.19.0. - pnpm 11.24.0, matching the root
package.json. - Docker with Compose v2 only when using the PostgreSQL profile or S3 compatibility harness.
- macOS or Linux for the optional POSIX shell-loading examples. Application commands are otherwise platform-independent.
Use the exact .nvmrc version to reproduce CI. Build and test jobs exchange source-bound outputs
and require identical Node.js and pnpm versions. A floating major version can select different
cached patch versions on separate runners. Update the runtime pin deliberately and verify the
complete static, unit and service-backed gates; retain the exact archive and version checks.
pnpm install --frozen-lockfile
pnpm checkThe lockfile must not change during installation. pnpm also enforces a minimum package release age and an explicit native-build allowlist. The repository check guide explains the combined package task graph, uncached validation and separate service-backed gates.
Run the API and console without creating an environment file:
pnpm devThe default endpoints are:
- API: http://127.0.0.1:4318
- OpenAPI contract: http://127.0.0.1:4318/openapi.json
- Console: http://127.0.0.1:3000
Evidence exists only in API process memory in this profile. Restarting the API intentionally clears all traces.
The committed Compose definition pins PostgreSQL 16.15 by image digest, initializes checksums with a deterministic locale and UTC timezone, publishes only to loopback, and stores database files in a named volume. The credentials in the example are intentionally local-only.
Prepare and load the durable profile before starting Compose so an optional port override applies to both Docker and the application URLs:
cp config/postgres.env.example .env
set -a
. ./.env
set +a
pnpm dev:db:upApply every immutable migration with the administrative URL, then create the isolated runtime roles. Provisioning is idempotent and rotates passwords for roles it previously marked as managed. It refuses to adopt an unrelated existing PostgreSQL role.
pnpm db:migrate
pnpm db:provision
pnpm db:status
pnpm devThe evidence API connects as proofstack_api, not as the database administrator. The separately
provisioned proofstack_identity role can execute only the fixed credential lifecycle functions;
it cannot read identity base tables or evidence. The proofstack_artifact_maintenance role can
inspect and advance artifact lifecycle rows but cannot create reservations or access evidence,
identity, outbox, sequences, or schema administration. The API verifies the complete migration
ledger at startup and readiness checks. The proofstack_replay_worker role can execute only the
fixed claim, heartbeat, reservation, reconciliation, observation, cancellation-acknowledgement,
and terminal-transition functions; it cannot read or mutate replay tables directly, publish
definitions, create jobs, request cancellation, or use API authority.
The proofstack_evaluation_worker role can read the immutable evaluation graph and execute only
the narrow result-persistence authority; it cannot publish criteria, sources, evaluator/oracle
specifications, runs, or assessments, and it has no direct table or outbox write privilege.
The proofstack_policy_author role can read exact immutable release-policy graphs and execute only
the public policy-publication and lifecycle-append functions; it cannot call their internal insert
helpers, mutate policy tables directly, write the outbox directly, or substitute for another
runtime role.
Stop the local database
without deleting evidence with:
pnpm dev:db:downStarting it again with pnpm dev:db:up reuses the named volume. Re-running migrations and
provisioning is safe and reports the already-current or updated state.
Bootstrap is an explicit administrative operation; the API never creates a first owner or key from an unauthenticated request. Set the required values in the current shell, using the narrowest useful capabilities and resource scope, then run the one-time command:
export PROOFSTACK_IDENTITY_TENANT_ID=ten_local
export PROOFSTACK_BOOTSTRAP_ACTOR_PRINCIPAL_ID=usr_local_operator
export PROOFSTACK_BOOTSTRAP_KEY_NAME=local-agent
export PROOFSTACK_BOOTSTRAP_KEY_CAPABILITIES=evidence:ingest,evidence:read
export PROOFSTACK_BOOTSTRAP_KEY_RESOURCE_SCOPE='{"mode":"tenant"}'
pnpm db:identity:bootstrapThe JSON response contains value exactly once. Copy that complete value immediately into an
untracked secret store; it cannot be recovered from PostgreSQL. Do not commit it, paste it into an
issue, or pass it in a URL. Remove the temporary bootstrap variables from the shell afterward.
To start the API in workload-key mode, set PROOFSTACK_AUTH_MODE=api_key. The committed PostgreSQL
profile already contains the distinct least-privilege PROOFSTACK_IDENTITY_DATABASE_URL. Set
PROOFSTACK_API_KEY only for the example process, then run:
export PROOFSTACK_AUTH_MODE=api_key
export PROOFSTACK_API_KEY='<complete value returned once by the bootstrap command>'
pnpm dev:apiFrom a second shell with the same PROOFSTACK_API_KEY, pnpm example:basic-agent sends authenticated
evidence. The server reads only the Authorization: Bearer header; query parameters, URLs, and
cookies are never API-key transports. pnpm db:identity:status reports aggregate active, expired,
revoked, and total counts for PROOFSTACK_IDENTITY_TENANT_ID without returning prefixes, hashes, or
secret material. The browser console never accepts workload secrets. Its sign-in UI is not yet
connected to the OIDC backend, so use the documented browser endpoints directly when validating an
OIDC deployment.
OIDC mode requires the durable identity database, an exact HTTPS issuer, and an exact HTTPS callback
registered with the provider. Put an HTTPS reverse proxy in front of the API and forward the fixed
callback path /v1/auth/oidc/callback; ProofStack constructs callback validation from the configured
URI and never trusts a request Host header. The proxy and certificate are deployment
responsibilities at this checkpoint.
Create a local authorization binding with the migration connection. The issuer and subject must exactly match the validated ID token. Roles, capabilities, tenant, and resource scope come only from this ProofStack record, never from an email, group, domain, or tenant claim:
export PROOFSTACK_IDENTITY_TENANT_ID=ten_local
export PROOFSTACK_BOOTSTRAP_ACTOR_PRINCIPAL_ID=usr_local_operator
export PROOFSTACK_OIDC_BINDING_ID=oidc_local_operator
export PROOFSTACK_OIDC_ISSUER='https://identity.example.test/tenant'
export PROOFSTACK_OIDC_SUBJECT='provider-subject-001'
export PROOFSTACK_OIDC_PRINCIPAL_ID=usr_local_operator
export PROOFSTACK_OIDC_ROLES=owner
export PROOFSTACK_OIDC_CAPABILITIES=project:read,project:manage,evidence:read,identity:read,identity:manage
export PROOFSTACK_OIDC_RESOURCE_SCOPE='{"mode":"tenant"}'
pnpm db:oidc:createGenerate a new transaction key into an untracked secret store, then configure and start the API. Do not reuse this example command's output across installations or commit it:
export PROOFSTACK_OIDC_TRANSACTION_SECRET="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
export PROOFSTACK_AUTH_MODE=combined
export PROOFSTACK_CORS_ORIGIN='https://console.example.test'
export PROOFSTACK_OIDC_CLIENT_ID='proofstack-console'
export PROOFSTACK_OIDC_CLIENT_SECRET='<provider client secret>'
export PROOFSTACK_OIDC_ISSUER='https://identity.example.test/tenant'
export PROOFSTACK_OIDC_REDIRECT_URI='https://proofstack.example.test/v1/auth/oidc/callback'
export PROOFSTACK_OIDC_SCOPES='openid profile email'
pnpm dev:apiOpen /v1/auth/oidc/login?returnTo=/ through the public HTTPS API endpoint. ProofStack uses
Authorization Code + PKCE S256, nonce, one-time state, and a short-lived browser-bound interaction
cookie. A successful callback creates a random server-side session and redirects only to the local
path stored in the encrypted transaction. GET /v1/auth/session returns current authorization.
Cookie-authenticated state changes, including POST /v1/auth/oidc/logout, require the exact allowed
Origin, an X-ProofStack-CSRF header, and the matching readable __Host-proofstack_csrf cookie.
To change authorization without changing provider identity, set the binding, actor, tenant, roles,
capabilities, and scope variables and run pnpm db:oidc:update. To terminate future logins and make
existing sessions fail their authoritative binding check, set a bounded reason and run:
export PROOFSTACK_OIDC_DISABLE_REASON='access removed'
pnpm db:oidc:disableThe optional object-storage profile runs the digest-pinned SeaweedFS version used by CI. It exposes only the S3 port on loopback, disables upstream telemetry and the administrative UI, uses a named volume, and has fixed credentials that are safe only for local testing. This harness verifies the adapter by itself; it does not wire artifact routes or continuously scheduled maintenance workers into the API. The additive profile and guarded bucket setup used to wire it into the durable replay reference are documented in the durable replay guide. Scoped one-shot maintenance commands are documented in the operations guide.
Start the service:
pnpm dev:object-storage:upRun the real-service object-store contract from another terminal:
export PROOFSTACK_TEST_S3_ACCESS_KEY_ID=proofstack-local
export PROOFSTACK_TEST_S3_SECRET_ACCESS_KEY=proofstack-local-secret
export PROOFSTACK_TEST_S3_ENDPOINT=http://127.0.0.1:8333
export PROOFSTACK_TEST_S3_REGION=us-east-1
pnpm test:integration:s3The test creates one random proofstack-test-* bucket, runs the immutable object-store contract,
and deletes that bucket. Stop the service without deleting its named volume with:
pnpm dev:object-storage:stopThe combined pnpm test:integration:artifacts acceptance requires both PostgreSQL and the S3
service. It provisions isolated runtime roles, creates a random bucket, and proves interrupted
activation, expiration, abandoned cleanup, purge retry, and key-reference status through the real
adapters. It is destructive to its random test scope and must never target production services.
Production bucket, policy, versioning, TLS, credential, compatibility, monitoring, and recovery requirements are defined in the artifact object-storage operations guide.
From another terminal, load the same profile if you created one, then check liveness, readiness, and send a real SDK trace:
set -a
test ! -f .env || . ./.env
set +a
curl --fail-with-body http://127.0.0.1:4318/health/live
curl --fail-with-body http://127.0.0.1:4318/health/ready
pnpm example:basic-agent
pnpm example:incident-to-regression
pnpm example:interaction-captureThe example sends an agent.run event and its child tool.execute event, waits for delivery, and
prints the generated trace ID and console URL. It uses fail-closed delivery so an unavailable API
cannot produce a false successful demonstration.
The incident-to-regression example emits a separate failed run, freezes its exact observed events as an immutable evidence-only fixture, publishes and reads an exact dataset version, and verifies both definition digests. It uses development authentication and therefore refuses non-loopback endpoints. The incident-to-regression guide documents the browser and workload authentication split, idempotent retry contract, failure semantics, and why this checkpoint is not executable replay.
The interaction-capture example emits a failed model/tool trace, reserves and uploads eleven fixture-dedicated classified artifacts, publishes one exact recorded-interaction successor, verifies metadata and explicitly acknowledged content exports, runs one exact recorded-boundary flow and one forced mismatch outside the API process, and then revokes and purges the complete content set. The default memory profile is sufficient for this disposable demonstration; stopping the API removes its remaining metadata. The interaction-capture guide documents capture authority, secret inspection, retry, interoperability, and revocation. The recorded-boundary replay guide documents exact matching, denied fallback, cooperative runtime inputs, and same-process isolation limits.
The durable replay example additionally requires PostgreSQL, the object-storage profile, the
additive untracked config/durable-replay.env.example profile, and the dedicated replay-worker
database role. It publishes immutable releases and plans, creates durable jobs, launches separate
worker and target processes, and proves success, running cancellation, stale-fence rejection,
lease recovery, budget reconciliation, and durable result artifacts. Follow the complete start,
verification, stop, authority, and limitation procedure in the
durable replay guide; do not run it against the disposable memory
profile.
The complete retained Workflow 1 acceptance has a separate single-command clean-checkout guide. Its runner owns isolated PostgreSQL and object-storage services on random loopback ports and removes their volumes after the test, so it should not be mixed with this guide's long-lived development profiles.
The API also accepts OTLP 1.11 trace requests at POST /v1/traces. The default loopback
development profile needs the project and environment headers but no credential. A production
authentication mode additionally requires a workload API key with evidence:ingest and access to
the requested scope. Follow the exact curl request, exporter variables, mapping, partial-success,
redaction, and retry guidance in the
OTLP/HTTP ingestion operations guide.
| Variable | Default | Owner | Purpose |
|---|---|---|---|
PROOFSTACK_ENV |
development |
API/database CLI | Runtime safety mode |
PROOFSTACK_AUTH_MODE |
development |
API | development, api_key, oidc, or combined |
PROOFSTACK_HOST |
127.0.0.1 |
API | Listen address; development auth requires explicit loopback |
PROOFSTACK_PORT |
4318 |
API | Listen port |
PROOFSTACK_LOG_LEVEL |
info |
API | Structured log level |
PROOFSTACK_CORS_ORIGIN |
unset | API | Exact allowed browser origin when cross-origin access is needed |
PROOFSTACK_STORAGE_MODE |
memory |
API | memory or postgres evidence adapter |
PROOFSTACK_DATABASE_URL |
unset | API | Least-privilege runtime database URL in PostgreSQL mode |
PROOFSTACK_POLICY_AUTHOR_DATABASE_URL |
unset | API | Distinct policy-author URL required in PostgreSQL mode; never substitute the general API URL |
PROOFSTACK_POLICY_EVALUATION_CONTROL_DATABASE_URL |
unset | API | Required dedicated policy control URL in PostgreSQL mode; separate from evidence, author, identity and worker authority |
PROOFSTACK_IDENTITY_DATABASE_URL |
unset | API | Distinct least-privilege identity URL required outside development auth |
PROOFSTACK_ARTIFACT_DATABASE_URL |
unset | artifact maintenance | Dedicated lifecycle-worker database URL |
PROOFSTACK_REPLAY_WORKER_DATABASE_URL |
unset | replay example/worker | Dedicated least-privilege worker URL; never substitute the migration or API URL |
PROOFSTACK_ARTIFACT_STORAGE_MODE |
disabled |
API | Use s3_local_keyring with PostgreSQL for persistent classified content; memory mode always uses disposable in-process storage |
PROOFSTACK_ARTIFACT_ACTIVE_KEY_ID |
unset | API | Exact active local artifact-key identifier in the experimental persistent profile |
PROOFSTACK_ARTIFACT_KEYS |
unset | API | Strict JSON object of key IDs to canonical base64url 32-byte keys; experimental and forbidden in production |
PROOFSTACK_ARTIFACT_S3_BUCKET |
unset | API | Existing dedicated artifact bucket for the persistent profile |
PROOFSTACK_ARTIFACT_S3_ENDPOINT |
AWS default | API | Optional S3-compatible endpoint; plaintext is allowed only on loopback outside production |
PROOFSTACK_ARTIFACT_S3_EXPECTED_BUCKET_OWNER |
unset | API | Optional exact AWS account owner assertion |
PROOFSTACK_ARTIFACT_S3_FORCE_PATH_STYLE |
false |
API | Explicit path-style addressing toggle for compatible local services |
PROOFSTACK_ARTIFACT_S3_REGION |
unset | API | Required S3 region for persistent artifact storage |
PROOFSTACK_OIDC_CLIENT_ID |
unset | API | Provider client identifier required by OIDC modes |
PROOFSTACK_OIDC_CLIENT_SECRET |
unset | API | Provider client secret required by OIDC modes |
PROOFSTACK_OIDC_ISSUER |
unset | API/identity CLI | Exact HTTPS issuer; also selects the binding during create |
PROOFSTACK_OIDC_REDIRECT_URI |
unset | API | Exact registered HTTPS callback without query or fragment |
PROOFSTACK_OIDC_SCOPES |
openid profile email |
API | Unique printable scopes including openid |
PROOFSTACK_OIDC_TRANSACTION_SECRET |
unset | API | Canonical base64url encoding of a dedicated random 32-byte key |
PROOFSTACK_OTLP_COMPRESSED_BODY_LIMIT_BYTES |
1048576 |
API | Maximum OTLP HTTP body bytes before decompression; hard maximum 64 MiB |
PROOFSTACK_OTLP_DECOMPRESSED_BODY_LIMIT_BYTES |
1048576 |
API | Maximum OTLP body bytes after gzip expansion; hard maximum 64 MiB |
PROOFSTACK_OIDC_BINDING_ID |
unset | identity CLI | Opaque binding identifier for create, update, or disable |
PROOFSTACK_OIDC_SUBJECT |
unset | identity CLI | Exact provider subject used only during binding create |
PROOFSTACK_OIDC_PRINCIPAL_ID |
unset | identity CLI | Stable ProofStack user principal used during binding create |
PROOFSTACK_OIDC_ROLES |
unset | identity CLI | Unique comma-separated authorization roles |
PROOFSTACK_OIDC_CAPABILITIES |
unset | identity CLI | Unique comma-separated authorization capabilities; may be empty on update |
PROOFSTACK_OIDC_RESOURCE_SCOPE |
unset | identity CLI | Strict JSON tenant or restricted project/environment scope |
PROOFSTACK_OIDC_DISABLE_REASON |
unset | identity CLI | Bounded audited reason required to disable a binding |
PROOFSTACK_MIGRATION_DATABASE_URL |
unset | database CLI | Administrative migration and provisioning URL |
PROOFSTACK_API_DATABASE_ROLE |
proofstack_api |
database CLI | Managed API role name |
PROOFSTACK_ARTIFACT_DATABASE_ROLE |
proofstack_artifact_maintenance |
database CLI | Managed artifact lifecycle role name |
PROOFSTACK_IDENTITY_DATABASE_ROLE |
proofstack_identity |
database CLI | Managed identity role name |
PROOFSTACK_PUBLISHER_DATABASE_ROLE |
proofstack_publisher |
database CLI | Managed outbox publisher role name |
PROOFSTACK_CONSUMER_DATABASE_ROLE |
proofstack_consumer |
database CLI | Managed consumer role name |
PROOFSTACK_EVALUATION_WORKER_DATABASE_ROLE |
proofstack_evaluation_worker |
database CLI | Managed evaluation result worker role name |
PROOFSTACK_MODEL_EVALUATION_WORKER_DATABASE_ROLE |
proofstack_model_evaluation_worker |
database CLI | Managed model-evaluation result worker role name |
PROOFSTACK_POLICY_AUTHOR_DATABASE_ROLE |
proofstack_policy_author |
database CLI | Managed release-policy author role name |
PROOFSTACK_HUMAN_REVIEWER_DATABASE_ROLE |
proofstack_human_reviewer |
database CLI | Managed human-review record writer role name |
PROOFSTACK_REPLAY_WORKER_DATABASE_ROLE |
proofstack_replay_worker |
database CLI | Managed replay worker role name |
PROOFSTACK_API_DATABASE_PASSWORD |
unset | database CLI | API role password used only during provisioning |
PROOFSTACK_ARTIFACT_DATABASE_PASSWORD |
unset | database CLI | Artifact lifecycle role password used only during provisioning |
PROOFSTACK_IDENTITY_DATABASE_PASSWORD |
unset | database CLI | Identity role password used only during provisioning |
PROOFSTACK_PUBLISHER_DATABASE_PASSWORD |
unset | database CLI | Publisher role password used only during provisioning |
PROOFSTACK_CONSUMER_DATABASE_PASSWORD |
unset | database CLI | Consumer role password used only during provisioning |
PROOFSTACK_EVALUATION_WORKER_DATABASE_PASSWORD |
unset | database CLI | Evaluation worker role password used only during provisioning |
PROOFSTACK_MODEL_EVALUATION_WORKER_DATABASE_PASSWORD |
unset | database CLI | Model-evaluation worker role password used only during provisioning |
PROOFSTACK_POLICY_AUTHOR_DATABASE_PASSWORD |
unset | database CLI | Release-policy author password used only during provisioning |
PROOFSTACK_HUMAN_REVIEWER_DATABASE_PASSWORD |
unset | database CLI | Human reviewer role password used only during provisioning |
PROOFSTACK_REPLAY_WORKER_DATABASE_PASSWORD |
unset | database CLI | Replay worker role password used only during provisioning |
PROOFSTACK_IDENTITY_TENANT_ID |
unset | identity CLI | Explicit tenant for bootstrap and aggregate status |
PROOFSTACK_BOOTSTRAP_ACTOR_PRINCIPAL_ID |
unset | identity CLI | Audited local operator identifier for bootstrap |
PROOFSTACK_BOOTSTRAP_KEY_NAME |
unset | identity CLI | Printable display name for the initial workload key |
PROOFSTACK_BOOTSTRAP_KEY_CAPABILITIES |
unset | identity CLI | Unique comma-separated delegable capabilities |
PROOFSTACK_BOOTSTRAP_KEY_RESOURCE_SCOPE |
unset | identity CLI | Strict JSON tenant or restricted project/environment scope |
PROOFSTACK_BOOTSTRAP_KEY_EXPIRES_AT |
90 days | identity CLI | Optional ISO 8601 expiry, bounded to 1 minute–365 days |
PROOFSTACK_POSTGRES_PORT |
5432 |
Compose | Loopback host port for the local database |
PROOFSTACK_S3_PORT |
8333 |
Compose | Loopback host port for the local S3-compatible harness |
PROOFSTACK_API_URL |
http://127.0.0.1:4318 |
Web/example | API base URL |
PROOFSTACK_API_KEY |
unset | SDK example | Complete one-time-issued key; never used by the API server or browser console |
PROOFSTACK_PROJECT_ID |
prj_local |
Web/example | Local project scope |
PROOFSTACK_ENVIRONMENT_ID |
env_local |
Web/example | Local environment scope |
PROOFSTACK_SOURCE_REVISION |
current Git HEAD |
durable replay example | Optional exact 40- or 64-character lowercase source object ID |
If PROOFSTACK_POSTGRES_PORT changes, update every database URL in .env to the same port. When
rotating a runtime password, update its runtime URL and matching provisioning variable, then run
pnpm db:provision before restarting the API. Never commit .env, a bootstrap response, or a
complete API key, and never place production credentials in an example file.
Use pnpm db:status to distinguish missing or pending migrations from an API problem. The command
returns nonzero until the bundled migration ledger is current. A PostgreSQL readiness failure is
intentional when the database is unavailable or its migration history is incomplete or corrupted.
If port 5432 is occupied, change PROOFSTACK_POSTGRES_PORT and both database URLs in .env. If port
8333 is occupied, set PROOFSTACK_S3_PORT and use the same port in
PROOFSTACK_TEST_S3_ENDPOINT. Then start the relevant Compose profile again. If development
authentication starts in production or on a non-loopback listener, report it as a security issue;
both configurations must cause immediate startup refusal.
For a routine stop, use pnpm dev:db:down for PostgreSQL or pnpm dev:object-storage:stop for the
S3-compatible harness; both named volumes are retained. The following command is destructive and
permanently deletes all local ProofStack PostgreSQL evidence and object-store data in this Compose
project:
docker compose down --volumesAfter destructive reset, repeat pnpm dev:db:up, pnpm db:migrate, and pnpm db:provision before
starting the durable API, and restart the object-storage harness before running its integration
test.