Witnora Hosted is the canonical product entry point. / is the public product
site, /evidence is the anonymous assurance snapshot, and /app is the authenticated operational
surface for organizations, projects, agents, runs, runtime actions, incidents,
and private evidence. /bench publishes research results and downloadable
verification resources. Existing /demo links remain a compatibility alias
for /evidence; the recorded refund demonstration is at
/demo/shopify-refund-assurance.
This is an operator reference. For a first connection, start with Get started or the design-partner quickstart.
Workspace Surface
The authenticated workspace is organized around four customer decisions rather than the control plane's internal resources:
- Overview: current business tasks, requests needing a decision, and a bounded summary of recent execution evidence. Pending action requests expose Approve and Reject directly to authorized reviewers.
- Agents: registration, connection status, and each Agent's tasks, rules, actions, versions, and connections.
- Improvements: failures, proposed fixes, verification, and regression follow-up.
- Activity & Evidence: activity history, verified results, coverage, audit trails, and the original records behind a result.
Settings separates personal, project, organization, and platform settings. Project settings include Notifications, Nora & models, Automation, and Advanced. Specialized credentials and manual evidence recovery are under Advanced; team access is under Members & roles. Existing API resources remain available.
Interface language
The workspace supports English and Simplified Chinese. Use EN / 中文 in the sidebar to switch without leaving the current page. The preference is retained in this browser and shared with the marketing page; it is not an account-wide preference. Forms, current selections, and conversations stay open when switching.
Product labels and explanations are localized. Customer names, task text, code,
API values, original evidence and existing conversation messages remain verbatim.
New Nora requests include an optional locale of en or zh-CN; deterministic
answers use that language and model requests receive the same presentation
instruction. Unsupported locale values are rejected. Language does not change
authorization, grants, evidence contents, or signing inputs.
Role-aware next action
GET /v1/projects/{projectId}/overview returns currentAssurance and exactly
one nextAction. The server resolves active incidents, pending high-risk
approvals, assurance freshness, and evidence completeness in that order. The
result includes the actor's permission, destination, rationale, and stable v0.2 schema version.
Next-action explainability and audit
The overview also returns nextActionHistory under
agentcert.next_action_decision.v0.3. Each append-only entry records the
matched rule, the bounded input summary, evaluator identity and role, current
decision, previous decision, SHA-256 decision fingerprint, and occurrence
time. The primary action and notification link include the exact assurance
case, runtime action, incident, or run identifier when one exists.
Overview evaluation performs an idempotent reconciliation against the latest
stored fingerprint. The first evaluation establishes a baseline without
email. A material recommendation change writes the decision and any
next_action_changed notification jobs in one Postgres transaction guarded
by a project advisory lock. Identical refreshes, concurrent readers, actor
role changes, and lower-priority input noise do not append history or email.
The transition history is available in Activity & Evidence -> Audit trail.
Recommended Production Profile
- Render Web Service: one Docker deployment serves the React console and Node API on the same origin.
- Supabase Postgres: production system of record.
- Supabase Auth: open email/password registration and email verification.
- Supabase Storage: private
agentcert-evidencebucket for screenshots, DOM, traces, reports, and evidence bundles. - Redis-compatible key value: shared rate limits and idempotency locks for multi-instance-safe request coordination. Postgres remains the durable queue.
This keeps the initial production footprint to two vendors. The application
code still uses ordinary Postgres and an ArtifactStore interface, so another
Postgres or S3-compatible provider can replace Supabase later.
Security Boundaries
- Supabase secret credentials are server-only.
- Browser sessions use the publishable key and a short-lived user access token.
- Agent/CI API keys are scoped to one project and stored only as SHA-256 hashes.
- API key metadata can be listed and active keys can be revoked by owners or admins; internal key hashes are never returned by the API.
- Agent credentials cannot approve or reject actions.
- Agent credentials cannot register identities or grant permissions; only a human owner or admin can change that authorization boundary.
- Production refuses to start without Postgres and Supabase configuration.
- Development authentication refuses to listen on non-loopback interfaces and
cannot run with
NODE_ENV=production. - Evidence downloads are authenticated and proxied by the control plane.
- Individual HTTP uploads are bounded by
WITNORA_MAX_ARTIFACT_BYTES. - Stored evidence is additionally bounded per run and project. Quota checks are serialized in Postgres, so concurrent uploads cannot race past the cap.
- The server validates extension, MIME type, evidence kind, and file signature for PNG/JPEG/WebP, JSON/JSONL, HTML, PDF, and ZIP. Direct executable file signatures are rejected even when the file is renamed.
- Run analysis reports evidence as
complete,partial, orrejected; this status is computed from server upload state and companion-artifact events, not accepted as a client assertion. - Every application table has Postgres row-level security enabled with no client policy. Supabase Data API clients cannot bypass the control plane.
- API responses include
x-request-id; Render receives structured JSON access and error logs containing method, path, status, and duration, never request bodies or authorization headers.
Local Development
The supported local debugging boundary does not inherit production Supabase, Postgres, Redis, email, Nora, or GitHub App credentials. It uses loopback-only development authentication, the in-memory control-plane store, local evidence files, and an ephemeral signing key:
npm run local:debug:install
npm run local:debug
Open http://127.0.0.1:8787/app. The local workspace signs in automatically as
developer@localhost. A second terminal can exercise the customer CLI against
the local server by adding --server http://127.0.0.1:8787 to the generated
onboarding command. Verify the complete boundary with:
npm run local:debug:verify
npm run onboarding:contract:report
The onboarding contract packs and installs the release-candidate CLI, creates a fresh local project for each immutable Node HTTP, Node MCP, and Python HTTP fixture, and runs every fixture three times through Action, approval, Probe, signed Receipt, and idempotent retry. It never creates a production project or uses an external secret.
GET /live is process liveness and remains independent of vendors. GET /health
is readiness: it returns 503 with sanitized dependency codes when
Postgres or Supabase Auth cannot serve customer traffic. Render uses /live so
an external outage is visible without turning dependency failure into a process
restart loop.
To verify an npm release candidate, including the packaged CLI lifecycle, local debug boundary, and the full onboarding contract, run:
npm run release:candidate:verify
This command prepares evidence only. It does not publish to npm.
Manual development command
npm --prefix packages/agentcert-dashboard run build
npm --prefix packages/agentcert-control-plane install
npm --prefix packages/agentcert-control-plane run build
$env:WITNORA_DEV_MODE="true"
$env:HOST="127.0.0.1"
$env:PORT="8787"
$env:WITNORA_DASHBOARD_DIR="../../public-demo/agentcert-monitor"
npm --prefix packages/agentcert-control-plane start
Open http://127.0.0.1:8787/ for the product site,
http://127.0.0.1:8787/evidence for the public snapshot, or
http://127.0.0.1:8787/app for the workspace. Development mode uses an in-memory database,
loopback-only auth, and local artifact files.
Production Environment
Required:
NODE_ENV=production
HOST=0.0.0.0
PORT=10000
WITNORA_PUBLIC_URL=https://app.your-domain.com
DATABASE_URL=postgresql://...
SUPABASE_URL=https://<project-ref>.supabase.co
SUPABASE_PUBLISHABLE_KEY=sb_publishable_...
SUPABASE_SECRET_KEY=sb_secret_...
WITNORA_STORAGE_BUCKET=agentcert-evidence
WITNORA_DASHBOARD_DIR=/app/public-demo/agentcert-monitor
WITNORA_MAX_ARTIFACT_BYTES=20971520
WITNORA_PROJECT_STORAGE_BYTES=1073741824
WITNORA_RUN_STORAGE_BYTES=104857600
WITNORA_EVIDENCE_RETENTION_DAYS=90
WITNORA_EVIDENCE_CLEANUP_INTERVAL_MS=86400000
WITNORA_EVIDENCE_CLEANUP_BATCH=500
# Render Blueprint injects REDIS_URL from agentcert-coordination.
WITNORA_RATE_LIMIT_REQUESTS=300
WITNORA_RATE_LIMIT_WINDOW_MS=60000
WITNORA_WEBHOOK_WORKER_INTERVAL_MS=2000
WITNORA_WEBHOOK_WORKER_BATCH=20
WITNORA_NOTIFICATION_WORKER_INTERVAL_MS=5000
WITNORA_NOTIFICATION_WORKER_BATCH=20
# Optional platform-owned email delivery. Users never provide SMTP credentials.
RESEND_API_KEY=re_...
WITNORA_ALERT_FROM_EMAIL=Witnora <alerts@your-verified-domain.com>
Never expose DATABASE_URL or SUPABASE_SECRET_KEY to the browser,
GitHub Pages, source control, or a client-side build variable.
Deployment Walkthrough
1. Create Supabase
- Sign in at
https://supabase.com/dashboardand choose New project. - Select the region closest to the Render region you will use.
- Save the generated database password in a password manager.
- Open SQL Editor and run every numbered file in
packages/agentcert-control-plane/migrations/in order. Existing deployments can run only newly added files; all migrations are idempotent. - Click Connect, choose Session pooler, and copy the port
5432connection string. Use this value asDATABASE_URL; session mode is the appropriate choice for a persistent Render service on an IPv4 network.
2. Configure Authentication
- Open Authentication -> Sign In / Providers -> Email.
- Enable Allow new users to sign up.
- Keep Confirm Email enabled for production.
- Open Authentication -> URL Configuration.
- Set Site URL to the canonical product URL:
https://witnora.com. - Add
https://witnora.comunder Redirect URLs. Keep the generated Render service URL only as a temporary recovery redirect if needed. - Before public launch, configure Authentication -> Emails -> SMTP Settings with Resend, Postmark, SES, or another production SMTP provider. Supabase's built-in mail service is restricted and is not a production delivery system for arbitrary public signups.
3. Create Private Object Storage
- Open Storage and select New bucket.
- Name it
agentcert-evidence. - Keep Public bucket disabled. Private is the default.
- Set the bucket file-size limit to at least
20 MB, or lowerWITNORA_MAX_ARTIFACT_BYTESto match. - Do not add public read policies. The Witnora server writes with the secret key and proxies authenticated downloads.
4. Copy Supabase Credentials
From Project Settings -> API Keys, record:
- Project URL ->
SUPABASE_URL - publishable key (
sb_publishable_...) ->SUPABASE_PUBLISHABLE_KEY - secret key (
sb_secret_...) ->SUPABASE_SECRET_KEY
The publishable key is intentionally returned by /v1/config for browser auth.
The secret key must exist only in Render. Existing deployments may continue to
use SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY as compatibility
fallbacks, but new deployments should use the current key types above.
5. Deploy on Render
- Sign in at
https://dashboard.render.comwith GitHub. - Choose New -> Blueprint.
- Select the
Kakarottoooo/witnorarepository. Render reads the rootrender.yamlandDockerfile.control-plane. - Enter all
sync: falsevalues when prompted:WITNORA_PUBLIC_URL,DATABASE_URL,SUPABASE_URL,SUPABASE_PUBLISHABLE_KEY, andSUPABASE_SECRET_KEY. - The Blueprint creates the private
agentcert-coordinationRender Key Value service and injects its internal connection string asREDIS_URL; do not paste a hostname or aredis-clicommand into the web service manually. - Set
WITNORA_PUBLIC_URLto the initialhttps://...onrender.comURL. - Deploy and wait for
/healthto reportcoordination.backend=redis,state=ready, andshared=true. - Open the service URL, create an account, confirm the email, and verify that the first organization/project is created.
6. Add a Custom Domain
- In Render, open the web service and choose Settings -> Custom Domains -> Add Custom Domain.
- Attach
witnora.comas the canonical domain. A futureapp.witnora.comsplit is optional and should only be introduced with a matching routing plan. - Render shows the exact DNS record. In your domain registrar, add that CNAME record and wait for Render to verify TLS.
- Change
WITNORA_PUBLIC_URLin Render tohttps://witnora.comand redeploy. - In Supabase Authentication -> URL Configuration, change Site URL to the same address and add it as an exact Redirect URL.
- Create a fresh test account using an email address outside your Supabase organization to verify public registration and SMTP delivery.
7. First External Agent
- Sign in to Witnora and start the connection flow in Agents. Follow Get started for the released CLI and customer-owned Gateway setup. Confirm the Agent's exact task and permitted action paths.
- Complete browser authorization. Standard onboarding creates a restricted credential automatically. For a custom integration only, use Settings -> Advanced -> Credentials & access -> Create credential and copy the secret immediately; only its hash is retained.
- Run the project-specific command provided by onboarding. For custom CI, use
the values under Settings -> Advanced -> Advanced configuration and
store
WITNORA_BASE_URL,WITNORA_PROJECT_ID, andWITNORA_API_KEYin the CI secret manager. - Submit one test run through the connected path and confirm that it appears in Activity & Evidence.
- Open the run, inspect its ordered events and evidence bundle, then confirm or correct one failure label. Human reviews retain confidence, first divergence, artifact pointers, supporting signals, and the reviewer's identity. Project API keys can read analysis but cannot write human reviews.
- Propose a high-risk action and confirm that the Agent credential cannot approve it, while an authorized human reviewer can approve or reject the exact request in Overview -> Needs Attention.
- Revoke the disposable test credential under
Settings -> Advanced -> Credentials & access and confirm subsequent
requests with that key return
401. Do not revoke a credential used by another active integration.
The hosted console is the canonical operational UI. The checked-in static monitor remains a deterministic public evidence snapshot and compatibility view; new interactive evidence analysis and review workflows belong in the hosted run workspace rather than a second stateful frontend.
Existing CLI users can publish without adopting an SDK:
npx witnora@latest onboard --project your-project-id
npx witnora@latest push --evidence .witnora/latest/agentcert-evidence.json
The CLI automatically uploads local companion artifacts referenced by the
bundle. It only reads files under --artifact-root (default: the current
directory), rejects path and symlink escapes, and enforces fixed limits of 25
files, 10 MiB per file, and 50 MiB per push. The run timeline records uploaded
and skipped counts plus bounded skip reasons. --no-artifacts preserves the
bundle-only behavior for restricted environments.
Before upload, the CLI adds an agentcert.artifact_manifest.v0.1 declaration
containing each companion artifact's normalized path, SHA-256 digest, byte
size, and kind. The bundle is stored first. Every later companion upload is
checked against that stored declaration before object storage. Undeclared or
mismatched bytes return 422 and mark the run's latest evidence attempt as
rejected.
Evidence Storage Governance
The production defaults are 1 GiB stored evidence per project, 100 MiB per
run, and 90-day retention. A quota violation returns 413; an unsupported,
mislabeled, malformed, or executable artifact returns 415. A rejected upload
does not leave object metadata behind, and run analysis exposes the rejection
reason rather than presenting existing artifacts as complete evidence.
The accepted server formats are PNG, JPEG, WebP, JSON, JSONL, HTML, PDF, and ZIP. ZIP is accepted for browser traces and portable evidence archives, but this release validates only its container signature; it does not inspect or execute archive members. Non-image downloads, including HTML and ZIP, are served as attachments.
The server runs bounded cleanup shortly after startup and then on the configured interval. Cleanup deletes the private storage object through the provider API before deleting its Postgres metadata. If object deletion fails, metadata is retained so the record can be retried and audited. Operators can run the same bounded task once during maintenance:
node packages/agentcert-control-plane/dist/cli.js cleanup-evidence
Storage quota, object count, and retention are visible on the project overview. Each run shows evidence bytes, the earliest expiry date, and one of:
complete: a v0.1 manifest is present and every declared path, SHA-256, byte size, and kind exactly matches the hosted object;partial: a bundle or referenced companion artifact is missing or skipped;rejected: the most recent upload attempt violated storage policy.
Older bundles without a manifest remain readable but are reported as
partial with legacy reconciliation status.
Enterprise legal hold
Evidence is deleted after 90 days by default. Project owners and admins can
apply for a legal hold from the Evidence view or API. A requested hold
does not pause cleanup. Only a platform administrator listed in
WITNORA_PLATFORM_ADMIN_EMAILS can approve, reject, or release it, and the
requester cannot approve their own application. Approval represents an
operator decision that enterprise eligibility and preservation scope have
been verified outside the application.
# Project owner/admin
curl -X POST "$WITNORA_URL/v1/projects/$PROJECT_ID/legal-holds" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason":"Preserve evidence for an active enterprise legal matter."}'
# Platform administrator
curl -X POST "$WITNORA_URL/v1/admin/legal-hold-requests/$REQUEST_ID/approve" \
-H "Authorization: Bearer $PLATFORM_ADMIN_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reviewNote":"Enterprise eligibility and legal scope confirmed."}'
Approved holds exempt the whole project from scheduled evidence cleanup until
an administrator calls the corresponding /release endpoint. Releasing a
hold does not immediately delete data; it makes expired objects eligible for
the next bounded cleanup pass.
Governed project erasure
The global Projects page is the lifecycle authority. Owners and admins first archive a project, which revokes active credentials and stops new activity while keeping existing records readable. They may then move it to Recently Deleted. The project, Agents, rules, runs, and evidence remain restorable for 30 days; restoring does not reactivate revoked credentials, so the Agent must reconnect.
After the recovery window, bounded maintenance permanently erases the project.
An owner or admin can also use the explicit Danger Zone action before the
deadline. Immediate erasure requires the exact project name plus a separate
irreversibility acknowledgement, deletes retained artifact bytes before project
records, and returns a witnora.project_erasure_receipt.v0.1 receipt. The
service fails closed if object storage cleanup fails. Requested and approved
legal holds block both manual and scheduled erasure; API keys and
non-administrative project roles cannot invoke either lifecycle operation.
Open Registration
The console displays Create account whenever /v1/config reports Supabase
auth. Supabase controls whether registration and email confirmation are enabled.
On first confirmed sign-in, POST /v1/onboarding/bootstrap creates an isolated
organization, owner membership, and clearly named assurance project.
External Agent Interfaces
- REST: openapi/control-plane-v1.yaml
- TypeScript:
packages/agentcert-sdk - Python:
packages/agentcert-sdk-python - MCP stdio adapter:
packages/agentcert-mcp-adapter
The machine path is intentionally separate from the human dashboard. Agents submit intent, runs, events, observed state, and evidence through the API; they do not scrape or operate the dashboard.
Universal ingestion and API hardening
Framework adapters should prefer the Universal Event/Action Envelope. Machine API keys are project-scoped and carry explicit scopes. New keys can use the full ingestion preset or a read-only preset; no API key can approve/reject actions, manage agent permissions, or decide legal holds.
Machine run, event, action, envelope, completion, and verification routes
accept Idempotency-Key. The server stores the request
hash and response for 24 hours. Reusing the same key and body replays the
response; reusing it with a different body returns 409. Authenticated traffic
is subject to a fixed-window limit and returns 429 plus Retry-After when
exhausted. When REDIS_URL is configured, limits and in-flight idempotency
locks are shared across instances. Without Redis the service stays available
with a single-process fallback and reports coordination.state=degraded from
/health and the project Trust Operations endpoint.
WITNORA_RATE_LIMIT_REQUESTS=300
WITNORA_RATE_LIMIT_WINDOW_MS=60000
Signed webhooks
Owners/admins can register HTTPS webhook endpoints for run.completed,
action.approved, action.rejected, action.verified, and
evidence.accepted. Witnora signs timestamp + "." + rawBody with
HMAC-SHA-256 and sends:
X-Witnora-Event
X-Witnora-Event-Id
X-Witnora-Timestamp
X-Witnora-Signature: v1=<hex digest>
Secrets are shown once and encrypted at rest with AES-256-GCM. Configure a stable 32-byte base64url or 64-hex key:
WITNORA_WEBHOOK_ENCRYPTION_KEY=<32 byte key>
Trust Operations v0.5 writes each webhook event and email notification to a
Postgres queue before returning to the caller. Workers claim jobs with leases and FOR UPDATE SKIP LOCKED, record
every delivery attempt, retry failed requests with bounded exponential backoff,
and move exhausted jobs to a dead-letter queue after five attempts. Expired
worker leases are reclaimable, so a process restart does not lose queued work.
The Dashboard shows pending, retrying, and dead-letter counts plus recent
failure details. It also persists scheduled production-smoke outcomes and shows
7-day smoke success, webhook latency, retry, and dead-letter trends. Redis,
server signing, scheduled smoke, webhook delivery, email delivery, and SLO burn
rate each expose a separate
operator-facing alert with a concrete reason. Delivery is at least once;
receivers must deduplicate using
X-Witnora-Event-Id.
Production-smoke failures are deduplicated by project and fingerprint. The
incident lifecycle is open -> investigating -> recovered -> resolved.
Owners/admins acknowledge an open incident with a rationale. One passing smoke
records progress but does not recover it; two consecutive passing smokes append
recovery evidence. An owner/admin must then review that evidence and explicitly
resolve the incident.
The operations response includes 30- and 90-day 99% SLO attainment, remaining error budget, and burn rate. It also evaluates paired 1h/6h fast-burn and 6h/24h sustained-burn windows. Fast burn requires at least three samples in both windows and thresholds of 14.4x/6x. Sustained burn requires at least three 6-hour and six 24-hour samples and thresholds of 6x/3x. These figures use completed scheduled production smokes only. Missing or stale schedules remain a separate alert, so absence of data cannot look healthy.
Owners/admins can add recipients in Settings -> Notifications and choose opened, regressed, recovered, and resolved notifications. Witnora sends a 24-hour ownership-verification link before activation. Provider credentials remain platform-side; users configure only recipient addresses and alert types. Delivery failures are retained in the notification attempt ledger, retried by the background worker, and moved to a manually replayable DLQ after five attempts. They never roll back an incident transition.
For production acceptance without a third-party endpoint, owners can open
Settings -> Advanced -> Advanced configuration and select
Enable delivery self-check.
Witnora creates one run.completed webhook targeting its own public
receiver. The receiver accepts only a body with a valid five-minute timestamp,
matching event headers, and the exact HMAC signature over the received bytes.
It stores no duplicate payload; the durable job and attempt log remain the
audit record.
Scheduled production acceptance
.github/workflows/production-smoke.yml runs daily and can also be dispatched
manually. It checks health and shared Redis coordination, idempotent replay and
conflict handling, evidence upload/download byte equality, historical-key
signature verification, run completion, signed webhook delivery through the
self-test receiver, and the Trust Operations status.
Each run persists a sanitized pass/fail health sample before the final status
check. A failed workflow creates one GitHub issue titled
[Witnora] Production trust smoke failure; subsequent failures append to the
same open issue. A recovery comment is added only after two consecutive passing
smokes. The issue remains open until the Witnora incident is explicitly
resolved; the next smoke reconciliation then closes it. Operators follow the
Trust Operations incident runbook.
Configure these GitHub repository Actions secrets:
WITNORA_PROJECT_ID=<production smoke project ID>
WITNORA_API_KEY=<project-scoped ingestion key>
The uploaded workflow artifact contains IDs and check results only. It never contains the API key or authorization headers.
Retention audit
Every cleanup attempt writes an immutable deletion-journal row containing the evidence digest, object key, size, reason, outcome, timestamp, and failure text. Platform administrators can review, approve, reject, and release legal holds in the Governance view and export a project report containing policy, active evidence, hold history, and the deletion journal.
The overview continuously exposes reviewed failure coverage, reviewed-label
precision, and correction rate under
agentcert.failure_quality_metrics.v0.1. New JSON evidence bundles record a
bounded failure-pattern count at ingestion; failed-run count is the fallback
for legacy bundles.
Platform administrators also receive 7/30/90-day pilot reports in the same
Governance view. agentcert.pilot_funnel.v0.2 cohorts projects by creation
time, measures sequential project/key/CLI/evidence conversion, reports median
stage duration, and aggregates bounded onboarding-friction reasons. The JSON
export intentionally excludes API-key hashes, evidence bytes, user email, and
arbitrary feedback context.
Hosted evidence signing and verification are documented in Evidence Trust Chain v0.1.