Backend-enforced delegated access for autonomous Agents, built on the Volc Agent Launchpad.
NawGate keeps Human, Agent, and Run authority separate. A human’s
access does not automatically become an Agent’s access: the backend owns Agent
identity and grants, each Run receives short-lived authority, and every
registered protected action is decided and enforced at RuntimeGateway.
The repository also preserves the starter platform: Agent CRUD, a browser Playground, persistent workspaces, multi-turn Codex sessions, local/container execution, and Ark or OpenAI-compatible model configuration.
[!WARNING] NawGate is a hackathon proof of concept. It protects registered actions routed through
agentctlandRuntimeGateway; it does not intercept arbitrary Codex shell commands, filesystem operations, or network requests. Do not use real production data or credentials. See SECURITY.md.
| Layer | Current implementation | Responsibility |
|---|---|---|
| NawGate middleware | Fastify services, bouncer-v5, risk-v1, RuntimeGateway |
Identity, policy, approval, enforcement, revocation, and safe evidence. |
| Agent Runtime | Codex CLI in a host process or disposable container | Executes Agent tasks, edits workspace files, and may request registered actions through agentctl. |
| Model provider | Volcengine Ark or an OpenAI-compatible Responses API | Supplies model inference to the Runtime and optional Team DAG planner; it is never an authorization authority. |
Codex CLI is the Agent Runtime adapter used by this Launchpad implementation;
it is not an architectural dependency of NawGate. A different Agent Runtime
can integrate by receiving backend-issued Run credentials and routing its
registered protected actions through RuntimeGateway.


PolicyEngine decides; RuntimeGateway enforces and owns the final protected
side effect.bouncer-v5 policy and backend-derived risk-v1 tiers.ALLOW, DENY, and REQUIRE_APPROVAL outcomes with unknown action,
resource, identity, or authority denied by default.content.moderate, content.disclose, content.publish, and
content.export actions.NawGate’s primary TechJam story is backend-enforced identity and authorization. The model may request an action, but it cannot choose the authenticated human, Agent owner, Run, Team, grant, risk tier, approval outcome, or protected side effect. Those facts are resolved and enforced by trusted backend services.
User A’s Agent can read project-a; it cannot read User B’s project-b.
Production deployment pauses for the owner, finalizes one exact one-use claim,
executes at most once after a final authority recheck, and produces redacted
evidence. See the NawGate overview,
standards alignment, and
complete demo script.
Explore the interactive system architecture, Agent/Team Run workflow, and protected-action sequence. GitHub-readable companions are available for the architecture, workflow, and sequence.
flowchart LR
Human[Human principal] --> UI[React Web UI]
UI --> API[Fastify control plane]
API --> Agent[AgentService]
Agent --> Route{Solo or Team Run}
Route --> Solo[MiddlewareRunner]
Route --> Team[TeamOrchestrator and TeamDAGRunner]
Team --> Solo
Solo --> Runtime[Agent Runtime: current adapter Codex CLI]
Runtime --> Provider[Ark or OpenAI-compatible model]
Runtime -. registered action via agentctl .-> Gateway[RuntimeGateway]
Gateway --> Policy[bouncer-v5, risk-v1, grants, approvals]
Gateway --> Protected[Protected resources and destinations]
API --> State[(JsonStore, audit chain, flight replay)]
Team --> State
Gateway --> State
| Capability | Demo action | Expected evidence |
|---|---|---|
| Agent lifecycle and multi-turn continuity | Follow workspace persistence. | Two successful Runs reuse one workspace and Codex thread. |
| Deterministic DLP | Submit the sample key/email prompt in the DLP step. | UI and persisted evidence contain redaction markers, not the submitted secret/PII. |
| Owner allow and cross-user hard deny | Run the authorization checks. | RuntimeGateway records ALLOW/SUCCESS for project-a and DENY/no side effect for project-b. |
| Approval and one-use authority | Run the restricted JIT approval. | Owner approval issues and consumes one exact claim; JIT succeeds once without changing the persistent Viewer role. |
| Team DAG and blackboard | Run the Team execution workflow. | Validated DAG, dependency-ready tasks, per-Agent output, and shared artifacts appear. |
| Team grant and restricted-file JIT | Follow Team enrollment and the Security Lab JIT flow. | Viewer remains viewer; exact temporary file authority succeeds once. |
| Revocation race protection | In the Security Lab, run Queued after revoke. | Initially allowed queued action becomes terminal DENY with no side effect. |
| Audit integrity and flight replay | Follow audit and replay. | Integrity state, hash-linked redacted events, and owner-only sanitized Run replay are visible. |
| Full fail-closed scenario set | In the Security Lab, run forged-input, replay, and Run/grant revocation checks. | Real-gateway denial and revocation evidence appears without a protected side effect. |
For the required three-minute recording, use sections 1, 2, 5, and 6 of the demo guide. Treat the Team membership and DAG sections as an extended path when additional time is available.
npm run poc is the canonical profile. It runs the React/Fastify control plane
on the host and starts every Agent turn in a disposable container containing
Codex CLI and agentctl.
Check the current terminal:
node --version
npm --version
docker info # Docker Desktop, Docker Engine, or Colima
podman info # Use this instead when running Podman
Only one engine is required. If Node 22 is installed with Homebrew on macOS:
brew install node@22
export PATH="$(brew --prefix node@22)/bin:$PATH"
hash -r
node --version
With nvm on macOS or Linux:
nvm install 22
nvm use 22
node --version
git clone https://github.com/CloudKai/NawGate.git
cd NawGate
cp .env.example .env
openssl rand -hex 24
Paste the generated value into APP_AUTH_TOKEN in .env, then choose exactly
one provider.
Option A — Volcengine Ark:
MODEL_PROVIDER=ark
ARK_API_KEY=your-ark-api-key
ARK_MODEL=ep-your-responses-endpoint-id
ARK_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
Option B — OpenAI or another OpenAI-compatible Responses endpoint:
MODEL_PROVIDER=openai-compatible
OPENAI_API_KEY=your-provider-api-key
OPENAI_MODEL=your-responses-capable-model-id
OPENAI_BASE_URL=https://api.openai.com/v1
Only the selected provider’s values are used. OpenAI replaces Ark as the model endpoint; it does not replace the Agent Runtime.
Run these as separate commands from the repository root:
set -a
source .env
set +a
npm run poc
Do not add trailing \ characters between these commands. A trailing backslash
would join the next line into the same shell command.
The startup script:
Codex CLI and agentctl are already installed in the POC image. A host Codex
installation and CODEX_BIN are not required for this profile.
Open http://localhost:3000 and enter the same
APP_AUTH_TOKEN stored in .env.
Create an Agent and run a normal first turn, then follow the complete NawGate demo for the protected-action, multi-Agent, DLP, audit, replay, and Security Lab flows.
Press Ctrl+C to stop. Remaining disposable Runtime containers for this POC
instance are removed; Agent workspaces and conversations persist.
Default state locations:
~/.volc-agent-launchpad/.local/ in the repositoryLOCAL_POC_DATA_ROOT| Profile | Intended use | Agent Runtime | Host Codex | Complete Playground protected-action demo |
|---|---|---|---|---|
npm run poc |
Recommended judge demo | Disposable container per turn | No | Yes |
| Docker Compose | ECS-style packaged app | Codex inside the application container | No | No; local-process credential restriction applies |
npm run dev |
UI/API development | Host local process | Yes, through CODEX_BIN |
No; use Security Lab or the container POC |
Protected-action credentials are deliberately not injected into local-process
Runs because the Agent and server child process share a filesystem. Normal
coding Runs work in every profile; use npm run poc for the complete
Playground → agentctl → RuntimeGateway demonstration.
Docker Compose packages the control plane and Codex CLI together in an ECS-style application container. It is useful for deployment checks, but it is not the recommended full protected-action judge path.
cp .env.example .env
# Fill APP_AUTH_TOKEN and one provider section.
docker compose --env-file .env config
docker compose up --build
Open http://localhost:3000. Stop without deleting Agent data:
docker compose down
Use this profile for Web/API iteration. It requires Node.js 22+, dependencies, and a host Codex executable:
npm install
cp .env.example .env # Skip if .env already exists.
The template leaves paths unset, so direct development uses safe repository
defaults rather than /app. Optional explicit values are:
APP_DATA_DIR=.local/data
AGENT_WORKSPACE_ROOT=.local/workspaces
CODEX_HOME=.local/codex-home
NAWGATE_GATEWAY_URL=http://127.0.0.1:3000
macOS with the ChatGPT application:
export PATH="$(brew --prefix node@22)/bin:$PATH"
set -a
source .env
set +a
export CODEX_BIN="/Applications/ChatGPT.app/Contents/Resources/codex"
"$CODEX_BIN" --version
npm run dev
Linux with Codex CLI installed globally:
npm install --global @openai/codex@0.111.0
set -a
source .env
set +a
export CODEX_BIN="$(command -v codex)"
"$CODEX_BIN" --version
npm run dev
If a Run reports spawn codex ENOENT, see troubleshooting below. This error is
about the host Agent Runtime executable, not the Ark/OpenAI API key.
| Variable | Template/default | Purpose |
|---|---|---|
HOST |
0.0.0.0 |
Control-plane listen address. |
PORT / PUBLIC_PORT |
3000 |
Server port and Compose host port. |
APP_AUTH_TOKEN |
Empty; required by POC | URL-safe browser unlock token. Use 24+ random characters. |
MODEL_PROVIDER |
ark |
Choose ark or openai-compatible. |
ARK_API_KEY / ARK_MODEL |
Empty | Required only for the Ark provider. |
ARK_BASE_URL |
Beijing v3 endpoint | Ark OpenAI-compatible API base. |
OPENAI_API_KEY / OPENAI_MODEL |
Empty | Required only for the OpenAI-compatible provider. |
OPENAI_BASE_URL |
https://api.openai.com/v1 |
Responses API base; may be another compatible provider. |
| Variable | Template/default | Purpose |
|---|---|---|
RUNTIME_PROVIDER |
local-process |
Direct-server default; npm run poc overrides to container. |
CODEX_BIN |
codex when unset |
Host executable for local-process development only. |
CODEX_SANDBOX_MODE |
workspace-write |
Inner Codex sandbox request; POC may fall back inside its outer container if Landlock is unavailable. |
CODEX_TIMEOUT_MS |
600000 |
Maximum Agent Runtime turn duration. |
CODEX_MAX_OUTPUT_BYTES |
2097152 |
Bound on captured Runtime output. |
NAWGATE_GATEWAY_URL |
Auto-selected | RuntimeGateway URL; leave unset for normal POC/local use. |
NAWGATE_APPROVAL_WAIT_MS |
90000 |
Bounded agentctl approval polling window; must be below CODEX_TIMEOUT_MS. |
NAWGATE_SECURITY_LAB_ENABLED |
true in demo template |
Enables judge/demo Security Lab; set false outside an intentional demo. |
| Variable | Template/default | Purpose |
|---|---|---|
APP_DATA_DIR |
Auto/default | JsonStore and flight data. Leave unset for POC path selection. |
AGENT_WORKSPACE_ROOT |
Auto/default | Persistent Agent workspace root. |
CODEX_HOME |
Auto/default | Codex configuration and session storage. |
LOCAL_POC_DATA_ROOT |
Platform-specific | Optional root overriding all POC state locations. |
CONTAINER_ENGINE |
Auto-detected by POC | Force docker or podman; Colima uses the Docker CLI. |
CONTAINER_RUNTIME_IMAGE |
volc-agent-runtime:local |
Disposable Agent Runtime image name. |
CONTAINER_CPU_LIMIT |
2 |
CPU limit per Runtime container. |
CONTAINER_MEMORY_LIMIT |
2g |
Memory limit per Runtime container. |
CONTAINER_PIDS_LIMIT |
256 |
Process limit per Runtime container. |
See .env.example for build mirror, package, user, and instance
overrides. Pre-rename environment aliases are not supported; use NAWGATE_*.
| Symptom | Cause and fix |
|---|---|
Node.js 22+ is required; found v20... |
Select Node 22 in the same terminal: nvm use 22, or prepend Homebrew’s node@22 directory to PATH, then run hash -r. |
EADDRINUSE ... port 3000 |
Another server owns the port. Run lsof -nP -iTCP:3000 -sTCP:LISTEN, verify the PID, and stop only that stale process—or use the healthy existing instance. |
ENOENT ... mkdir '/app' |
An older host .env exported container-only paths. Remove/comment APP_DATA_DIR=/app/data, AGENT_WORKSPACE_ROOT=/app/workspaces, and CODEX_HOME=/app/codex-home, or migrate values from the current template. |
| No Docker/Colima/Podman engine found | Start one engine and verify docker info or podman info. Leave CONTAINER_ENGINE unset for auto-detection. |
Agent Runtime cannot reach 127.0.0.1:3000 |
An older .env fixed NAWGATE_GATEWAY_URL. Remove/comment it so npm run poc selects the container-reachable host address. |
| Browser token is invalid | Enter the exact APP_AUTH_TOKEN loaded before startup. Restart the server after changing .env; do not print the token during a demo. |
| Provider/model not configured | Ensure MODEL_PROVIDER matches the filled Ark or OpenAI section and the model supports the Responses API. |
spawn codex ENOENT |
Only local-process development needs host Codex. Set CODEX_BIN to a working absolute path and restart, or use npm run poc. |
| Bind mount rejected | Set LOCAL_POC_DATA_ROOT to a directory shared with Docker/Colima/Podman. |
More platform-specific help is in Local POC.
Existing-ECS deployment:
cp .env.example .env.production
# Fill APP_AUTH_TOKEN and the selected provider values.
./scripts/deploy-existing-ecs.sh .env.production
Terraform deployment:
cp .env.example .env.production
cp deploy/volcengine/terraform.tfvars.example deploy/volcengine/terraform.tfvars
# Fill both files, then export the Volcengine infrastructure credentials.
./scripts/deploy-volcengine.sh
Set NAWGATE_SECURITY_LAB_ENABLED=false outside an intentional protected demo.
agentctl and
RuntimeGateway; it does not intercept arbitrary Agent Runtime activity.JsonStore, Team DAG orchestration, and blackboard state are single-process
POC components without high availability or distributed queues.npm run check
CONTAINER_ENGINE=docker npm run test:container # Requires a real container engine
docker compose --env-file .env config
terraform fmt -check -recursive deploy/volcengine
npm run check runs TypeScript checks, deterministic tests, and both builds.
npm run test:container is separately gated and must not be reported as passed
unless a real Docker/Podman container completed it.