This guide covers day-to-day WebCodex operations: server initialization, client enrollment, pairing, project registration, token management, and smoke testing. For first deployment, see QUICK_START.md. For production hardening, Nginx, QUIC, and OAuth2 details, see DEPLOYMENT.md.
Operator-friendly read-only checks are available through:
webcodex-cli ops status --server-url "$SERVER_URL" --token-file "$USER_TOKEN_FILE"
webcodex-cli ops agents --server-url "$SERVER_URL" --token-file "$USER_TOKEN_FILE"
webcodex-cli ops projects --server-url "$SERVER_URL" --token-file "$USER_TOKEN_FILE"
webcodex-cli ops smoke-preflight \
--server-url "$SERVER_URL" \
--token-file "$USER_TOKEN_FILE" \
--project agent:workstation:my-repo
webcodex-cli ops smoke-preflight \
--server-url "$SERVER_URL" \
--token-file "$USER_TOKEN_FILE" \
--project agent:workstation:my-repo \
--strictThese commands accept --server-url/--url, --env-file, --token-file,
--token, --json, and --strict. They require a user token/PAT or another
bearer token with suitable runtime/project/job read scopes. Prefer
--token-file for operator use; --token is supported for constrained
one-off calls but is easier to expose through shell history or process lists.
They do not print token or env values.
WARN means the check found something worth reviewing, but it is not
necessarily a deploy blocker. By default, ops commands exit 0 when they can
generate a report, even when Overall: FAIL. Add --strict for deployment
gates: PASS and WARN exit 0, while FAIL exits 2.
ops smoke-preflight short-circuits when the target project is missing,
offline, disconnected, or not git-backed. In that case it reports the blocking
reason without sending show_changes or workspace_hygiene_check to a stale or
offline agent.
webcodex-cli server init creates the server environment file containing the bootstrap admin token and runtime settings.
SERVER_URL="https://webcodex.example.com"
ENV_FILE="/etc/webcodex/webcodex.env"
DATA_DIR="/var/lib/webcodex"
BIN="/opt/webcodex/bin/webcodex"
CLI="/opt/webcodex/bin/webcodex-cli"
sudo "$CLI" server init \
--listen 127.0.0.1:8080 \
--data-dir "$DATA_DIR" \
--env-file "$ENV_FILE" \
--public-url "$SERVER_URL"This writes:
WEBCODEX_TOKEN— the bootstrap/admin token. Used only for initial setup, user creation, pairing, and emergency admin. Do not put it in GPT Actions, MCP, or agent config.WEBCODEX_ADDR— the server listen address.WEBCODEX_DATA— the data directory path.WEBCODEX_PUBLIC_URL— the public HTTPS URL.
The env file is server-side only. Do not copy it to client machines.
For one-off admin CLI commands, load the env file:
set -a
. "$ENV_FILE"
set +aOr pass --env-file "$ENV_FILE" when the command supports it.
sudo "$CLI" server install-service \
--env-file "$ENV_FILE" \
--bin "$BIN"
sudo systemctl daemon-reload
sudo systemctl enable --now webcodex
"$CLI" server status --env-file "$ENV_FILE"Use --overwrite only when replacing an existing unit.
For testing or environments without systemd:
# Foreground
WEBCODEX_ENV_FILE="$ENV_FILE" "$BIN"
# Background
nohup env WEBCODEX_ENV_FILE="$ENV_FILE" "$BIN" > /var/log/webcodex.log 2>&1 &Manual mode does not provide automatic restart, log rotation, or boot persistence. Use systemd for production.
Each client or user profile gets its own directory under /etc/webcodex/clients/:
/etc/webcodex/clients/<profile>/agent.toml
/etc/webcodex/clients/<profile>/projects.d/
/etc/webcodex/clients/<profile>/webcodex-user-token
/etc/webcodex/clients/<profile>/webcodex-agent-token
Enroll a client with a profile:
"$CLI" client enroll \
--server-url "$SERVER_URL" \
--pairing-code <wc_pair_...> \
--client-id workstation \
--display-name "Workstation" \
--profile workstation \
--allowed-root /root/gitInstall a profile-specific agent service:
"$CLI" agent install-service \
--profile workstation \
--bin /opt/webcodex/bin/webcodex-agent \
--overwrite
sudo systemctl daemon-reload
sudo systemctl enable --now webcodex-agent-workstationOlder setups may use flat paths directly under /etc/webcodex/:
/etc/webcodex/agent.toml
/etc/webcodex/projects.d/
/etc/webcodex/webcodex-user-token
/etc/webcodex/webcodex-agent-token
This layout does not support multiple clients on the same machine. Migrate to profile-based config when possible.
Pairing creates a short-lived code on the server side that the client exchanges to enroll. This avoids copying long-lived credentials between machines.
"$CLI" pairing create \
--server-url "$SERVER_URL" \
--env-file "$ENV_FILE" \
--username alice \
--client-id workstation \
--display-name "Alice Workstation" \
--ttl-secs 600This returns a wc_pair_* code. Send only this code to the client user.
"$CLI" client enroll \
--server-url "$SERVER_URL" \
--pairing-code <wc_pair_...> \
--client-id workstation \
--display-name "Alice Workstation" \
--profile alice \
--allowed-root /home/alice/git- Do not copy
WEBCODEX_TOKENto client machines. - Do not copy
wc_agent_*tokens between machines. - Do not copy
wc_pat_*tokens between machines. - Do not put the bootstrap token in agent config or GPT Action config.
- Each client should generate its own tokens through
client enrollortoken create-local.
register_project is an agent-level runtime tool. It registers an existing directory as a project on a connected agent.
{
"tool": "register_project",
"params": {
"client_id": "workstation",
"id": "my-repo",
"name": "My Repo",
"path": "/root/git/my-repo",
"allow_patch": true,
"overwrite": true
}
}Key behaviors:
- Does not require the project to already exist in the agent's
projects.d/. - Finds the online agent by
client_id. - The agent validates that
pathexists and is within itsallowed_roots. - The agent writes
projects.d/<id>.tomlon its own machine. - The resulting runtime project id is
agent:<client_id>:<project_id>(e.g.,agent:workstation:my-repo).
create_project creates a new directory and registers it. It is subject to the agent's allowed_roots policy.
{
"tool": "create_project",
"params": {
"client_id": "workstation",
"id": "tmp-smoke",
"name": "Temporary Smoke Project",
"path": "/root/git/tmp-smoke",
"git_init": true,
"allow_patch": true
}
}If allowed_roots is /root/git, then paths outside that root (e.g., /tmp/...) are rejected by default. For temporary or test projects, place them under the allowed root:
/root/git/tmp-smoke-project
- Server bootstrap/admin token.
- Created by
server init. - Lives only in the server env file (
/etc/webcodex/webcodex.env). - Used for: initial setup, creating users, issuing account credentials, pairing, emergency admin.
- Do not use for: GPT Actions, MCP, agent connections, daily runtime calls.
- Belongs to a user (owner).
- Generated locally by
webcodex-cli token create-local; the server stores only the hash. - Not bound to a single device — the same PAT works from any client.
- Used for: GPT Actions, MCP, REST API,
callRuntimeTool,tools/list,tools/call. - A single PAT can access multiple agents and projects under the same owner on the same server, provided the scopes are sufficient.
- Do not use for: agent WebSocket/QUIC connections.
- Belongs to an agent instance.
- Generated locally by
webcodex-cli agent-token create-local; the server stores only the hash. - Bound to a specific
client_id. - Used for:
webcodex-agentWebSocket/QUIC connections only. - Do not use for: GPT Actions, MCP, REST API calls.
- One-time credential issued by
webcodex-cli users create --issue-credential. - Used to locally create
wc_pat_*andwc_agent_*tokens. - Do not use for: GPT Actions, MCP, agent connections, or any ongoing auth.
- Delegated token issued via the OAuth2 authorization code flow.
- Used for: GPT Actions and MCP when OAuth2 is enabled.
- Requires
WEBCODEX_OAUTH2_ENABLED=trueon the server.
- Each agent has an
owner(the user who created or enrolled it). - Each PAT has an
owner(the user who generated it). - A PAT can only access agents and projects owned by the same user.
- Owner mismatch results in access denial.
The client_id is a stable identifier for an agent instance, typically named after the machine or role:
workstation
laptop
server-a
container-dev
Runtime project ids follow the pattern:
agent:<client_id>:<project_id>
Examples:
agent:workstation:my-repo
agent:laptop:my-repo
agent:server-a:service-api
agent:container-dev:tmp-smoke
The client_id portion identifies which agent hosts the project. The project_id portion is the local registry id from the agent's projects.d/*.toml file.
Create GPT Actions and MCP connectors per server, not per device. If a server hosts multiple agents owned by the same user, a single PAT can access all of them.
Example GPT/MCP app names:
WebCodex Production
WebCodex Staging
WebCodex Lab
Use a wc_pat_* personal API token. Generate one with:
"$CLI" token create-local \
--server "$SERVER_URL" \
--user alice \
--credential "$WEBCODEX_ACCOUNT_CREDENTIAL" \
--name gpt-action \
--scopes runtime:read,project:read,project:write,job:runDo not use:
WEBCODEX_TOKEN— admin-only.wc_agent_*— agent-only.wc_acct_*— one-time enrollment only.
| Scope | Purpose |
|---|---|
runtime:read |
Read runtime status, list tools, list agents. |
project:read |
Read files, search, git status/diff, show_changes. |
project:write |
Write files, apply patches, structured edits. |
job:run |
Run shell commands, Cargo helpers, Codex tasks. |
account:manage |
Optional: manage OAuth clients and tokens. |
When OAuth2 is enabled (WEBCODEX_OAUTH2_ENABLED=true), MCP clients can use the authorization code flow instead of a static PAT:
- No PAT needed in the client config.
- The client redirects to
https://your-domain.example/oauth/authorize. - After consent, a
wc_oat_*access token is issued. - Scopes are delegated from the authorizing user.
For static-token MCP clients:
- Use a
wc_pat_*in theAuthorization: Bearerheader. - Do not use
wc_agent_*orWEBCODEX_TOKEN.
For coding tasks, prefer the deterministic coding-task aggregate tools. They create and close out a session while keeping all continuity explicit.
{
"tool": "start_coding_task",
"params": {
"project": "agent:workstation:my-repo",
"title": "fix authentication bug",
"include_tool_manifest": true,
"bind_current": false
}
}Returns a wc_sess_* session id in output.session.session_id. Keep that id
and pass it explicitly to subsequent project tools. By default,
start_coding_task also returns compact output.tool_manifest without full
input/output schemas; set include_tool_manifest=false to omit it.
For bounded startup context, keep include_tool_manifest=true but pass
tool_manifest_categories such as ["workflow","session","git","edit", "artifact","cleanup"] and optionally tool_manifest_limit; the runtime clamps
the limit to 1..100 and reports whether the compact manifest was truncated. A
limit-driven truncated=true is expected bounded output, not ResponseTooLarge;
acceptance scripts should inspect the explicit limit and returned/total counts,
plus truncation_reason="limit", limit_applied=true, requested_limit,
returned_count, and total_count.
For lightweight MCP direct or GPT Action sanity, call startup with
include_runtime_status=true, compact_startup=true,
include_tool_manifest=true, and a small tool_manifest_limit. Compact startup
returns build version/commit/dirty state, tools.count, jobs.active_count,
agents.summary, and effective/agent/server project status without tools.names,
full agent policy, allowed_roots, shell profile internals, command text,
stdout/stderr, env values, tokens, secrets, or full config values. Full
include_runtime_status=true without compact_startup remains available for
deeper troubleshooting and can include non-secret observability details such as
the public URL, tool names, agent policy summary, and allowed roots.
Read output.startup_verdict.status first. If it is warn or fail, inspect
startup_verdict.checks and startup_verdict.suggested_next_actions; detailed
startup fields remain the audit source.
Standalone runtime_status also accepts summary_only=true or compact=true
for the same compact health shape. Use that for first-contact deployed sanity;
reserve full no-arg runtime_status for deeper troubleshooting.
Startup sanity verdict rules:
- PASS: compact runtime status is present,
tools.countis nonzero,jobs.active_count=0, an agent is online when the task depends on an agent project, and requested git/workspace status is clean. - WARN: runtime status or git/workspace was not requested, validation has not
run yet,
tool_manifest.truncated=truewithtruncation_reason="limit", or the requested git/workspace status is dirty (tracked, staged, untracked, or conflicted). Dirty workspace is an expected development state and does not prevent starting a coding task. Existing worktree changes must be inspected and preserved; they are not automatically reverted, stashed, cleaned, or overwritten. - FAIL: runtime status failed, blocking jobs are active, agent required for the task is offline, tool manifest generation failed, or another infrastructure / safety condition makes the project inaccessible or the requested work unsafe or impossible. Startup blocking is reserved for those conditions — not for a dirty Git worktree.
The response also includes output.permissions. The current self-hosted
development profile is policy=dev_auto_approve, auto_approve=true, and
human_approval_required=false; future release profiles should prefer
require_approval.
{"tool": "runtime_status", "params": {"summary_only": true}}
{"tool": "list_projects", "params": {}}
{"tool": "read_file", "params": {"project": "agent:workstation:my-repo", "path": "src/auth.rs"}}
{"tool": "search_project_text", "params": {"project": "agent:workstation:my-repo", "pattern": "authenticate", "path": "src"}}
{"tool": "show_changes", "params": {"project": "agent:workstation:my-repo", "session_id": "wc_sess_example", "include_diff": false}}When choosing a smoke target from list_projects, prefer
entries in projects whose capabilities.recommended_for_smoke=true. The
output shape is {count, projects, recommended_for_smoke}. For git smoke, also
require capabilities.git_available=true; a project such as
agent:special:test-mcp may be safe but not git-backed.
- Read and inspect the current worktree (
read_file,show_changes). Dirty worktrees are a valid baseline; protect existing user edits. Do not rebuild file content from HEAD and overwrite the current file. - Precise local edits:
apply_text_edits(canonical). Ordered exact replace/insert/delete with optional hash/prefix/anchor guards. - Multi-file / complex unified diffs:
apply_patch_checked(canonical). Preflight first; apply only when validation passes. Prefer over rawapply_patch. - New files or intentional whole-file rewrite:
write_project_file. Not the default for ordinary local edits. - Compatibility tools (
replace_line_range,insert_at_line,delete_line_range,replace_in_file,replace_exact_block,insert_before_pattern,insert_after_pattern) remain supported for special cases; preferapply_text_editsfor new workflows.
{"tool": "apply_text_edits", "params": {"project": "agent:workstation:my-repo", "path": "src/auth.rs", "edits": [{"kind": "replace_exact", "old_text": "old", "new_text": "new"}]}}
{"tool": "apply_patch_checked", "params": {"project": "agent:workstation:my-repo", "patch": "diff --git ..."}}
{"tool": "write_project_file", "params": {"project": "agent:workstation:my-repo", "path": "src/new.rs", "content": "fn main() {}\n"}}{"tool": "cargo_fmt", "params": {"project": "agent:workstation:my-repo"}}
{"tool": "cargo_check", "params": {"project": "agent:workstation:my-repo"}}
{"tool": "cargo_test", "params": {"project": "agent:workstation:my-repo"}}
{"tool": "validate_patch", "params": {"project": "agent:workstation:my-repo", "patch": "diff --git ..."}}Use run_shell only when structured Cargo helpers, validate_patch, and
apply_patch_checked are insufficient. run_shell is not classified as
validation by default. Use run_job for bounded async diagnostics/build/test
work, then supervise it with job_status, job_tail, or list_jobs. To stop a
WebCodex-started job, call stop_job through callRuntimeTool/MCP with the
same project, the returned job_id, the explicit session_id when available,
and confirm=true. stop_job enforces job project/session ownership and never
returns stdout/stderr. It keeps the compatibility stopped field, but models
should prefer stop_effect, terminal, terminal_pending, and final_status.
{
"tool": "show_changes",
"recording_session_id": "wc_sess_example",
"params": {
"project": "agent:workstation:my-repo",
"session_id": "wc_sess_example",
"include_diff": false,
"session_event_limit": 30
}
}{
"tool": "workspace_hygiene_check",
"params": {
"project": "agent:workstation:my-repo",
"session_id": "wc_sess_example"
}
}Review order for coding closeout is deterministic: call show_changes, inspect
clean, warnings, hunks_truncated, and suggested_next_actions; then call
workspace_hygiene_check, inspect clean, findings, warnings, and
suggested_next_actions; then use session_handoff_summary or
finish_coding_task with summary_only=true for compact canonical outcomes.
show_changes and workspace_hygiene_check expose top-level verdict
summaries; read them first, but keep the detailed fields as the auditable basis.
For final closeout reporting, use finish_coding_task.task_outcome,
finish_coding_task.evidence_history, and
finish_coding_task.evidence_integrity, not nested show_changes.verdict or
workspace_hygiene_check.verdict.
Discovery taxonomy is intentional: start_coding_task and
finish_coding_task are workflow category tools for the coding lifecycle.
start_session, bind_current_session, session_summary, and
session_handoff_summary are session category tools for raw ledger and
session-control workflows. Use category=workflow for lifecycle discovery and
category=session for session ledger/control discovery.
{
"tool": "finish_coding_task",
"params": {
"project": "agent:workstation:my-repo",
"session_id": "wc_sess_example",
"include_handoff": true,
"include_workspace": true,
"include_hygiene": true,
"include_validation_summary": true,
"include_diff": false,
"summary_only": true
}
}finish_coding_task and session_handoff_summary should be used with
summary_only=true for compact handoff and closeout checks. For handoff, also
pass include_workspace=true and include_validation=true. For finish, pass
include_workspace=true, include_hygiene=true,
include_validation_summary=true, include_diff=false, and keep
include_handoff=true when a handoff aggregate is useful.
finish_coding_task.include_workspace is a compatibility flag matching
session_handoff_summary.include_workspace: it controls the nested handoff
workspace block when include_handoff=true; the top-level finish
workspace/show_changes check keeps its existing default behavior.
For finish_coding_task, including summary_only=true, read final task
completion from output.task_outcome, validation history from
output.evidence_history, and assertion/evidence quality from
output.evidence_integrity. These canonical fields do not change
authorization, permissions, guards, session binding, expected-failure
classification, MCP direct errors, or job lifecycle behavior. Top-level
suggested_next_actions contains the bounded final closeout actions.
For summary_only=true final outputs, sanity checks should reject stdout/stderr
bodies, command text, tails, and excerpts. Raw lower-level diagnostic/status
payloads may contain empty string fields such as stderr: ""; treat non-empty
stdout/stderr bodies as sensitive/high-noise unless explicitly requested, and
never allow env values, tokens, or secrets to appear.
finish_coding_task and session_handoff_summary include a bounded jobs
section. active_count remains a compatibility broad active count. New fields
split it into blocking_active_count and nonblocking_active_count, with
running_count, stop_requested_count, and terminal_pending_count for model
closeout decisions. queued, running, started, and agent_queued are
blocking active states and produce active_jobs_present. stop_requested is
nonblocking terminal-pending state and produces jobs_terminal_pending with
blocking=false; it should not prompt "stop active jobs before proceeding" by
itself. The jobs summary includes only metadata such as job_id, kind,
status, project, and timestamps; it does not include raw stdout/stderr,
tails, excerpts, or command text.
Compact handoff/finish outcome rules:
- PASS:
workspace_clean=true,jobs.blocking_active_count=0,tool_failures.unexpected_count=0,tool_failures.expectation_mismatch_count=0,tool_failures.unexpected_success_count=0, andhygiene_clean=true. - WARN:
validation.status=not_runwith or without ledger-derivedreview_evidence, resolved historical validation failures are present (validation.status=mixed,latest_status=passed,historical_failures.resolved=true, andhistorical_failures.unresolved=false), resolved validation-like historical tool failures fromcargo_fmt,cargo_check, orcargo_testwere followed by passed structured validation while workspace and hygiene checks are clean, matched expected failures are present (expected_count>0while unexpected/mismatch/unexpected-success counts are all zero), non-git/git-unavailable review context, terminal-pending nonblocking jobs, or bounded startup/manifest/review output was truncated only because of an explicit limit. - FAIL: workspace is dirty, blocking jobs are active, unexpected tool failures exist, expected-failure mismatches exist, expected-failure calls unexpectedly succeeded, hygiene failed, validation failed, or mixed validation still has an unresolved/latest failure.
Unresolved validation failures and non-validation tool failures remain
blocking. Callers should inspect validation.historical_failures,
evidence_history.status, and evidence_integrity.warning_reasons to
distinguish resolved validation feedback from a clean first-pass run.
For a read-only handoff without finish aggregation:
{
"tool": "session_handoff_summary",
"params": {
"session_id": "wc_sess_example",
"project": "agent:workstation:my-repo",
"include_validation": true,
"summary_only": true
}
}Smoke and acceptance tests can mark intentional negative paths with runtime testing metadata:
{
"tool": "stop_job",
"params": {
"project": "agent:workstation:my-repo",
"session_id": "wc_sess_example",
"job_id": "missing-job",
"confirm": false,
"expected_failure": true,
"expected_failure_kind": "confirmation_required",
"assertion_name": "stop_job requires confirm=true"
}
}expected_failure, expected_failure_kind, and assertion_name are ledger
metadata only. They do not change authorization,
permission decisions, hard guards, execution, command_started, or the
immediate success/error result. finish_coding_task and
session_handoff_summary classify matching expected failures separately from
unexpected failures. They surface expectation_mismatch_count when the actual
failure_kind / error_kind differs, and unexpected_success_count when a
call marked expected_failure=true succeeds. Only unexpected failures,
mismatches, or unexpected successes should trigger "review failed tool calls"
style next actions; matched expected failures may produce an informational
expected failure assertions matched action.
For expected Cargo validation failures, use expected_failure=true with
expected_failure_kind=validation_failed. cargo_fmt, cargo_check, and
cargo_test set failure_kind="validation_failed" only when the underlying
Cargo command started and returned a nonzero exit code. Permission denials,
session/project mismatches, guard denials, timeouts, malformed arguments,
disconnected agents, commands that did not start, and runtime errors keep their
existing failure or error kind.
cargo_test reports zero-tests metadata when it can parse Rust test harness
output: tests_detected, tests_run_count, and zero_tests_run. The parser
sums all running N test / running N tests sections, so a mixed lib
running 0 tests plus integration running 1 test run is not considered
zero-tests. A successful cargo_test with zero_tests_run=true should not be
treated as strong validation; closeout summaries warn with
cargo_test_zero_tests and suggest checking the filter or command. If
expected_failure=true but cargo_test exits successfully after running zero
tests, it is still an unexpected success / invalid negative assertion.
cargo_fmt and cargo_check do not report zero-tests metadata.
In GPT Actions, that same expected negative path may still show an outer
tool_error because /api/tools/call returns HTTP 400 for a concrete runtime
ToolResult.success=false. Do not treat the outer GPT Action label alone as a
transport failure. Judge intentional negative-path smoke from the immediate
failure_kind / error_kind and from
session_handoff_summary(summary_only=true).tool_failures or
finish_coding_task(summary_only=true).tool_failures. The classifier separates
expected_count, unexpected_count, expectation_mismatch_count, and
unexpected_success_count; expected failures must not bypass auth, permission,
guards, session_project_mismatch, confirmation requirements, schema checks,
invalid JSON handling, or unknown-tool failure semantics.
finish_coding_task.validation and session_handoff_summary.validation are
ledger-derived summaries. They do not expose raw stdout/stderr, excerpt fields,
or validation_output_summary; the parser extracts only stable facts from safe
bounded metadata and does not infer root causes or suggest fixes. Summaries
include status and reason: events_total=0 yields status=not_run and
reason=no_validation_tool_invoked; all-success, all-failure, and mixed ledgers
yield passed, failed, and mixed. validation.status=mixed remains strict
ledger history. Summary outputs also include latest_status and
historical_failures; a mixed ledger with a later successful validation and no
unresolved historical failure may warn instead of fail. finish_coding_task
may also downgrade resolved historical cargo_fmt, cargo_check, or
cargo_test tool failures when later structured validation passed and the
workspace/hygiene checks are clean. Non-validation tool failures and unresolved
validation failures remain blocking. not_run means no structured validation
tool was invoked, so docs-only or read-only work should interpret it with task
context.
For cargo_test, validation events preserve parsed zero-tests metadata when
available. A successful zero-test run remains visible through closeout warnings
rather than counting as strong test coverage.
finish_coding_task.review_evidence and
session_handoff_summary.review_evidence are separate ledger-derived,
non-cargo review summaries. They count successful read/search/diff/workspace/
hygiene inspection tools such as read_file, search_project_text,
show_changes, git_diff_hunks, and workspace_hygiene_check.
finish_coding_task.review_evidence may include the closeout review calls that
finish_coding_task performs itself. Compact review evidence also includes a
bounded tools list for explainability. It never includes file contents,
stdout/stderr, diff hunks, command text, tokens, secrets, or raw input payloads.
For docs-only or read-only audit tasks, validation.status=not_run can coexist
with review_evidence.total>0; compact verdicts remain warn and use
validation_not_run_with_review_evidence instead of treating the task as passed.
Review evidence is not a replacement for structured validation.
finish_coding_task.permissions and session_handoff_summary.permissions
summarize high-risk permission decisions from the session ledger. A high-risk
tool is one that is not read-only, is destructive, or is shell/job-like according
to runtime metadata. Under dev_auto_approve, those tools record
status=auto_approved after hard safety checks pass. Auto approval does not
bypass auth, OAuth scopes, read-only sessions, explicit deny guards,
cross-project session mismatch denial, path safety, sensitive path denial, or
agent policy. The permission summaries are bounded metadata only and must not
contain stdout/stderr, command bodies, patches, file contents, env, tokens,
secrets, or excerpts. approved_count remains a compatibility manual approval
count; use manual_approved_count, auto_approved_count, and
total_approved_count for clear totals.
REST / GPT Action:
- Top-level
recording_session_id= recorder metadata for the current generic wrapper call; it is stripped before concrete tool dispatch. - Top-level
session_id= ordinary flattened tool input whenparams/argumentsare absent. params.session_id= business parameter used byshow_changesorsession_summaryto select which session to summarize.- The two may be the same or different.
tool_manifestis the recommended way to discover accepted flattened args. It returnsaccepted_flattened_argsanddeprecated_or_unsupported_argsper tool without full schemas.start_sessioncreates a session record but does not automatically bind future calls.session_handoff_summaryrequires explicitsession_id; it never implicitly uses current-session binding.
MCP:
_session_idin arguments = reserved recorder metadata. Stripped before tool dispatch.session_idin arguments = business parameter forshow_changesorsession_summary.- Current-session bindings are process-local in-memory convenience state, not the durable session ledger.
Use this sequence to verify a deployment without modifying any project.
Assumes a registered project agent:workstation:my-repo.
{"tool": "runtime_status", "params": {"summary_only": true}}Confirm service/build, tools.count, jobs.active_count, agent summary, and
project effective status. Use full no-arg runtime_status only when you need
deeper details such as output.permissions.policy; for development builds this
is normally dev_auto_approve, and release deployments should plan to use
require_approval.
{"tool": "list_agents", "params": {}}{"tool": "list_projects", "params": {}}{"tool": "start_session", "params": {"project": "agent:workstation:my-repo", "title": "smoke test"}}{"tool": "read_file", "params": {"project": "agent:workstation:my-repo", "path": "README.md", "start_line": 1, "limit": 10}}{"tool": "show_changes", "params": {"project": "agent:workstation:my-repo", "session_id": "wc_sess_example", "include_diff": false}}{"tool": "session_summary", "params": {"session_id": "wc_sess_example"}}After deploying a new server, agent, or runtime build:
- Refresh the GPT Action or MCP schema if runtime tool schemas changed.
- Run
tool_manifestor focusedlist_toolswithsummary_only=truepluscategory,features, orlimit; avoid fulllistRuntimeToolsin GPT Actions unless debugging schemas. Iftruncated=trueis caused by the caller-supplied limit,truncation_reason="limit"confirms it is a bounded response rather thanResponseTooLarge. - Run
runtime_status(summary_only=true)orruntime_status(compact=true); confirmprojects.effective.status,projects.effective.count, andprojects.agent_registered.online_count. Projects are registered by agents, not by server-sideprojects.toml. For workflow sanity, also usestart_coding_task(include_runtime_status=true, compact_startup=true)and inspectstartup_verdict.status; reserve full runtime status for deeper troubleshooting. - Confirm
start_coding_taskandfinish_coding_taskare available through the generic runtime tool path. - Confirm
session_handoff_summaryexposesvalidationwheninclude_validationdefaults to true. - On a
list_projects.projects[]entry withcapabilities.recommended_for_smoke=true, runstart_coding_task,read_fileorsearch_project_text,show_changes, andfinish_coding_task. - Run local or staging E2E and eval checks:
Preferred deployed generic sanity sequence:
runtime_status(summary_only=true)orruntime_status(compact=true).tool_manifest.tool_manifest(category=runtime),tool_manifest(category=session), andtool_manifest(category=git)for focused discovery.show_changes(include_diff=false)on the selected smoke project.workspace_hygiene_checkon the same smoke project.finish_coding_task(summary_only=true, include_workspace=true, include_hygiene=true, include_handoff=true, include_validation_summary=true, include_diff=false)with the explicitsession_id.
bash scripts/e2e_zero_config_ws.sh
E2E_TRANSPORT=polling bash scripts/e2e_zero_config_ws.sh
EVAL_MODE=compare bash scripts/eval_coding_loop.shUse this short runbook for a conservative binary deployment. Adjust service names and install paths to match the host, and keep token values in the operator's shell or secret manager rather than in commands, logs, or docs.
- Build the release binaries:
cargo build --release --bins- Back up the current install directory:
backup_dir="/opt/webcodex/bin.backups/$(date -u +%Y%m%dT%H%M%SZ)"
sudo install -d -m 0755 "$backup_dir"
sudo cp -a /opt/webcodex/bin/. "$backup_dir/"- Install the new binaries:
sudo install -m 0755 target/release/webcodex /opt/webcodex/bin/webcodex
sudo install -m 0755 target/release/webcodex-agent /opt/webcodex/bin/webcodex-agent
sudo install -m 0755 target/release/webcodex-cli /opt/webcodex/bin/webcodex-cli- Restart services on the appropriate hosts:
sudo systemctl restart webcodex
sudo systemctl restart webcodex-agent- Verify the public schema and operation budget:
curl -fsS https://webcodex.example.com/openapi.json > /tmp/webcodex-openapi.json
python3 - /tmp/webcodex-openapi.json <<'PY'
import json
import sys
schema = json.load(open(sys.argv[1], encoding="utf-8"))
ops = [
op.get("operationId")
for methods in schema.get("paths", {}).values()
for op in methods.values()
if isinstance(op, dict)
]
print(f"operation_count={len(ops)}")
if len(ops) > 30:
raise SystemExit("operation_count exceeds GPT Actions limit")
PYThe current recommended GPT Action operation count is 25, and it must remain at
or below 30. Runtime/MCP tools such as stop_job remain available through the
generic callRuntimeTool surface and do not add dedicated GPT Action operations.
- Run deployment smoke checks:
WEBCODEX_PUBLIC_URL="https://webcodex.example.com" \
WEBCODEX_TOKEN="<wc_pat_or_allowed_shared_key>" \
bash scripts/smoke_deployment.sh
WEBCODEX_SMOKE_RUN=1 \
WEBCODEX_PUBLIC_URL="https://webcodex.example.com" \
WEBCODEX_TOKEN="<wc_pat_or_allowed_shared_key>" \
bash scripts/smoke_artifact_transfer.shFor GPT Actions, re-import the schema from /openapi.json when needed, then run
a read-only discovery/status smoke before mutation. For MCP, reconnect the
client and run initialize, tools/list, and a read-only tools/call such as
runtime_status or list_projects.
GPT Actions and MCP should use a managed wc_pat_* token or a
deployment-allowed shared key. wc_agent_* is only for webcodex-agent; do not
copy it into GPT Actions or MCP configuration.
- Check service logs:
journalctl -u webcodex --since "15 minutes ago"
journalctl -u webcodex-agent --since "15 minutes ago"- Roll back from the backup if smoke or logs show a deployment regression:
sudo cp -a "$backup_dir"/. /opt/webcodex/bin/
sudo systemctl restart webcodex
sudo systemctl restart webcodex-agentDo not use production mutation as smoke coverage. Any write-path smoke must stay
inside a disposable test project or temporary project under an allowed root.
Use artifact paths such as artifacts/smoke/<name>.artifact or
artifacts/smoke/<name>.txt. For abort cleanup verification, prefer
artifact_upload_abort.final_file_exists or
read_project_artifact_metadata with allow_missing=true; do not use an
expected read failure to prove absence. In session summaries,
policy_rejected means policy blocked the request before a write.
{
"tool": "register_project",
"params": {
"client_id": "workstation",
"id": "my-repo",
"name": "My Repo",
"path": "/root/git/my-repo",
"allow_patch": true,
"overwrite": true
}
}{
"tool": "create_project",
"params": {
"client_id": "workstation",
"id": "tmp-smoke",
"name": "Temporary Smoke Project",
"path": "/root/git/tmp-smoke",
"git_init": true,
"allow_patch": true
}
}- DEPLOYMENT.md — production hardening, Nginx, QUIC, OAuth2.
- QUICK_START.md — first deployment walkthrough.
- AUTH_MODEL.md — credential model summary.
- GPT_ACTIONS.md — GPT Action setup and tool surface.
- MCP.md — MCP endpoint, client config, and troubleshooting.
- AGENT_PROJECTS.md — agent project registry format.