Skip to contentWitnora
Menu
Start / Updated 2026-09-06

Hosted workspace

Create a project, connect the CLI, and retain evidence safely.

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.

  • 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-evidence bucket 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, or rejected; 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

  1. Sign in at https://supabase.com/dashboard and choose New project.
  2. Select the region closest to the Render region you will use.
  3. Save the generated database password in a password manager.
  4. 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.
  5. Click Connect, choose Session pooler, and copy the port 5432 connection string. Use this value as DATABASE_URL; session mode is the appropriate choice for a persistent Render service on an IPv4 network.

2. Configure Authentication

  1. Open Authentication -> Sign In / Providers -> Email.
  2. Enable Allow new users to sign up.
  3. Keep Confirm Email enabled for production.
  4. Open Authentication -> URL Configuration.
  5. Set Site URL to the canonical product URL: https://witnora.com.
  6. Add https://witnora.com under Redirect URLs. Keep the generated Render service URL only as a temporary recovery redirect if needed.
  7. 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

  1. Open Storage and select New bucket.
  2. Name it agentcert-evidence.
  3. Keep Public bucket disabled. Private is the default.
  4. Set the bucket file-size limit to at least 20 MB, or lower WITNORA_MAX_ARTIFACT_BYTES to match.
  5. 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

  1. Sign in at https://dashboard.render.com with GitHub.
  2. Choose New -> Blueprint.
  3. Select the Kakarottoooo/witnora repository. Render reads the root render.yaml and Dockerfile.control-plane.
  4. Enter all sync: false values when prompted: WITNORA_PUBLIC_URL, DATABASE_URL, SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, and SUPABASE_SECRET_KEY.
  5. The Blueprint creates the private agentcert-coordination Render Key Value service and injects its internal connection string as REDIS_URL; do not paste a hostname or a redis-cli command into the web service manually.
  6. Set WITNORA_PUBLIC_URL to the initial https://...onrender.com URL.
  7. Deploy and wait for /health to report coordination.backend=redis, state=ready, and shared=true.
  8. Open the service URL, create an account, confirm the email, and verify that the first organization/project is created.

6. Add a Custom Domain

  1. In Render, open the web service and choose Settings -> Custom Domains -> Add Custom Domain.
  2. Attach witnora.com as the canonical domain. A future app.witnora.com split is optional and should only be introduced with a matching routing plan.
  3. Render shows the exact DNS record. In your domain registrar, add that CNAME record and wait for Render to verify TLS.
  4. Change WITNORA_PUBLIC_URL in Render to https://witnora.com and redeploy.
  5. In Supabase Authentication -> URL Configuration, change Site URL to the same address and add it as an exact Redirect URL.
  6. Create a fresh test account using an email address outside your Supabase organization to verify public registration and SMTP delivery.

7. First External Agent

  1. 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.
  2. 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.
  3. 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, and WITNORA_API_KEY in the CI secret manager.
  4. Submit one test run through the connected path and confirm that it appears in Activity & Evidence.
  5. 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.
  6. 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.
  7. 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.

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.