Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ Everything an operator chooses lives in `deploy/.env`, read by
| `ENGINE_AGENT_OPENCODE_CONFIG` | no | the image's policy | The opencode half of the driven-session policy: an opencode config with a `permission` block, given to every engine-launched opencode session as `OPENCODE_CONFIG_CONTENT` (the user's own config is not edited). Allow `gh pr merge` here where agents may merge their own PRs. `off` turns it off ([`ENGINE.md`, "Permission posture"](ENGINE.md#permission-posture)). |
| `ENGINE_AGENT_CODEX_POLICY` | no | the image file, else `/etc/codex/requirements.toml` | The Codex half. Codex itself reads `/etc/codex/requirements.toml` and no other path; the engine checks that file, and a named one too, is readable and wires the gitguard hook (`[[hooks.SessionStart]]` + `[[hooks.PreToolUse]]` running `/usr/local/bin/klaudia hook gitguard` with `failClosed = true`, plus the `[features] hooks = true` pin that stops a session switching hooks off) before a Codex launch. `/etc/codex/requirements.toml` and its directory must also be root-owned and not group- or world-writable, and `/usr/local/bin/klaudia` a root-owned regular file the same way; the hook always runs that image build, never a runtime `VOGT_KLAUDIA_VERSION` copy, so a gitguard fix ships only with an image rebuild (WI-1146). This is an accident guard, not a sandbox: the session user's passwordless sudo can defeat it. Empty checks `/etc/codex/requirements.toml`; the image's reference copy at `/usr/local/share/vogt/driven-session-codex-requirements.toml` without it is a refusal. `off` is the only way a deployment that has the file skips the check. A path that is missing, empty, unreadable or without that hook refuses the Codex launch (400) and does not fall through to bypass; Claude and opencode are not blocked. The shipped file wires the hook for the Codex fork (WI-1356) ([`ENGINE.md`, "Permission posture"](ENGINE.md#permission-posture)). |
| `ENGINE_SESSION_RSS_WARN` | no | off | Flag any session whose process tree's resident memory reaches this (`8GiB`). Usage is shown either way; this only marks the heavy ones. |
| `ENGINE_WORKTREE_GITHUB_TOKEN` | no | unset | GitHub token the engine uses when `session.start` fetches the worktree base from a GitHub `origin` (WI-1666). Set it to the same token sessions receive as `GH_TOKEN` (the manifest entry named by `ENGINE_AGENT_AUTH_GH_TOKEN_FROM`). A file is not used: the engine reads the variable and passes it to `GIT_ASKPASS` for that one fetch, and redacts it from errors. Unset, an `https://github.com` origin refuses the worktree start instead of failing as `Repository not found`. SSH GitHub origins and non-GitHub origins do not need it and keep the engine user's own git credentials. |
| `ENGINE_WORKTREE_CLEAN_ON_HIBERNATE` | no | off | When a session is hibernated or stopped and its directory is a linked git worktree, remove regenerable build output there (`target` beside a `Cargo.toml`, `node_modules`, `.venv`). A repo's main checkout is never touched, and a tracked file is never deleted ([`ENGINE.md`, "Worktree build output"](ENGINE.md#worktree-build-output)). |
| `ENGINE_DISK_WARN_PERCENT` | no | `85` | Flag the workspace volume on `sweep`, `status` and `engine.status` once this percent of it is used. A whole percent from 1 to 100; anything else fails the boot. |
| `ENGINE_ECONOMICS_TICK_SECS` | no | `15` | How often the engine reads each live session's transcript to meter its turns, context and compactions, reported on the session summary and as histograms on `GET /metrics` ([`ENGINE.md`, "Session economics"](ENGINE.md#session-economics)). `0` disables it. |
Expand Down
13 changes: 11 additions & 2 deletions docs/ENGINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -847,8 +847,17 @@ than these routes.
fails, or a base the remote does not have, refuses the start (`400`) rather
than falling back to the local ref. The fetch moves only that one
remote-tracking ref, never a local branch. The fetch runs as the engine
process, before the session process exists, so a private origin is reached
with the engine user's credentials rather than the session account's. Every other refusal (codex policy, agent launch) is checked before the
process, before the session process exists (WI-1666). An `https://github.com`
origin (host exactly `github.com`) is fetched with
`ENGINE_WORKTREE_GITHUB_TOKEN`, falling back to `GH_TOKEN` on the engine
process — the same token agent-auth aliases to `GH_TOKEN` inside a session.
The value is given to git only through `GIT_ASKPASS` (`vogt-git-askpass`,
reading `ENGINE_WORKTREE_FETCH_TOKEN` for that one command) and is never put
on an argument list or into an error. An https GitHub origin with neither
variable set refuses the start (`400`) and names
`ENGINE_WORKTREE_GITHUB_TOKEN`. SSH (`git@github.com:...`), a host that only
contains the substring `github.com`, and every non-GitHub origin keep the
engine user's own git credentials and are not given the token. Every other refusal (codex policy, agent launch) is checked before the
cut, and a start that fails after it (prompt file, PTY spawn) removes the
worktree and its branch again, so a refused start leaves neither behind.
Absent means the session opens in `cwd`, byte-identical to a request from
Expand Down
57 changes: 38 additions & 19 deletions engine/deploy/git-askpass.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail

prompt="${1:-}"
#!/bin/sh
set -eu
# Host is the exact hostname, not a substring.
# github.com.example and notgithub.com do not receive the GitHub token.
prompt=${1:-}
case "$prompt" in
*Username*github.com*)
printf '%s\n' 'x-access-token'
;;
*Username*)
printf '%s\n' 'git'
;;
*Password*github.com*)
[[ -n "${GH_TOKEN:-}" ]] || exit 1
*://*) host=${prompt##*://} ;;
*) host=$prompt ;;
esac
host=${host%%/*}
host=${host##*@}
host=${host%%:*}
host=${host%\'}
host=${host#\'}
case "$prompt" in
*[Uu]sername*)
if [ "$host" = "github.com" ]; then
printf '%s\n' x-access-token
else
printf '%s\n' git
fi
;;
*[Pp]assword*)
if [ "$host" = "github.com" ]; then
if [ -n "${ENGINE_WORKTREE_FETCH_TOKEN:-}" ]; then
printf '%s\n' "$ENGINE_WORKTREE_FETCH_TOKEN"
elif [ -n "${GH_TOKEN:-}" ]; then
printf '%s\n' "$GH_TOKEN"
;;
*Password*)
[[ -n "${GIT_AUTH_TOKEN:-}" ]] || exit 1
printf '%s\n' "$GIT_AUTH_TOKEN"
;;
*)
else
exit 1
fi
else
if [ -z "${GIT_AUTH_TOKEN:-}" ]; then
exit 1
;;
fi
printf '%s\n' "$GIT_AUTH_TOKEN"
fi
;;
*)
exit 1
;;
esac
Loading
Loading