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. The legacy GitHub Pages monitor remains an immutable
public evidence archive and links visitors to /evidence. Existing /demo
links are preserved as a compatibility alias for /evidence.
The authenticated workspace is organized around four customer decisions rather than the control plane’s internal resources:
Agent registration, connections, and team access live under Setup. Sandbox sandbox conformance and platform governance live under Advanced. Existing API resources and deep links remain available; this is a presentation-layer consolidation, not a second implementation of the assurance workflows.
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.
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 complete transition timeline is visible under Evidence & Audit.
agentcert-evidence bucket for screenshots,
DOM, traces, reports, and evidence bundles.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.
NODE_ENV=production.WITNORA_MAX_ARTIFACT_BYTES.complete, partial, or rejected; this
status is computed from server upload state and companion-artifact events,
not accepted as a client assertion.x-request-id; Render receives structured JSON access
and error logs containing method, path, status, and duration, never request
bodies or authorization headers.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.
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.
https://supabase.com/dashboard and choose New project.packages/agentcert-control-plane/migrations/ in order. Existing deployments
can run only newly added files; all migrations are idempotent.5432
connection string. Use this value as DATABASE_URL; session mode is the
appropriate choice for a persistent Render service on an IPv4 network.https://witnora.com.https://witnora.com under Redirect URLs. Keep the generated
Render service URL only as a temporary recovery redirect if needed.agentcert-evidence.20 MB, or lower
WITNORA_MAX_ARTIFACT_BYTES to match.From Project Settings -> API Keys, record:
SUPABASE_URLsb_publishable_...) -> SUPABASE_PUBLISHABLE_KEYsb_secret_...) -> SUPABASE_SECRET_KEYThe 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.
https://dashboard.render.com with GitHub.Kakarottoooo/witnora repository. Render reads the root
render.yaml and Dockerfile.control-plane.sync: false values when prompted:
WITNORA_PUBLIC_URL, DATABASE_URL, SUPABASE_URL,
SUPABASE_PUBLISHABLE_KEY, and SUPABASE_SECRET_KEY.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.WITNORA_PUBLIC_URL to the initial https://...onrender.com URL./health to report
coordination.backend=redis, state=ready, and shared=true.witnora.com as the canonical domain. A future app.witnora.com
split is optional and should only be introduced with a matching routing plan.WITNORA_PUBLIC_URL in Render to
https://witnora.com and redeploy.witnora connect command shown in
Integrations. For CI, set WITNORA_BASE_URL,
WITNORA_PROJECT_ID, and WITNORA_API_KEY in the secret manager.401.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.
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.
Owners and admins can archive a project and select Erase data in the project
navigator. The destructive operation requires an exact project-name
confirmation, deletes retained artifact bytes before deleting project records,
and returns a witnora.project_erasure_receipt.v0.1 JSON receipt. The service
fails closed if object storage cleanup fails. Requested and approved legal
holds block the operation; API keys and non-administrative project roles cannot
invoke it.
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.
packages/agentcert-sdkpackages/agentcert-sdk-pythonpackages/agentcert-mcp-adapterThe 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.
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
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 Integrations -> Email alerts 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
Integrations -> Trust operations and select Enable self-test receiver.
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.
.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.
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.