aivyx-coder · ManualContents ↓
Troubleshooting
First steps
- Check the log:
~/.config/aivyx-coder/aivyx.logrecords start-up problems and every permission decision. - Re-run setup:
aivyx-coder --setupre-detects your server, checks the model really answers, and reads its context window. - Capture the raw traffic: start with
AIVYX_DEBUG_LOG=/tmp/wire.log aivyx-coderto see exactly what goes to and from the model. The file holds everything in plain text — delete it when you’re done.
Common problems
Replies stop mid-sentence, or a turn ends having done nothing. Usually
the served context window is smaller than you think. Ollama serves its own
default (often 4096) unless the model sets num_ctx or the service sets
OLLAMA_CONTEXT_LENGTH; aivyx-coder warns about this at start-up. Set
[backend] context_tokens to the window the server really serves. On
llama-server with a reasoning model, a tool call can end up inside an
unclosed thinking block — start the server with
--chat-template-kwargs '{"enable_thinking": false}'. See
Local model servers.
Tool calls appear as plain text instead of running. The model’s chat
template is missing or doesn’t support tools: use a tool-capable model, run
llama-server with --jinja, and prefer GGUFs from Hugging Face over reused
Ollama blobs. On a small model, try --edit-format prompted.
A false “hidden context window” warning with Lemonade. Point
base_url at the llama-server process Lemonade started, not at Lemonade’s
gateway port — see Local model servers.
Commands fail that work in your own terminal. On Linux, commands run in
a sandbox. ssh-agent, gpg signing, docker and socket-based database
clients need [sandbox] allow_unix_sockets = true; tools that write to a
fixed /tmp path need share_system_tmp = true; test runners that create
process groups (cargo-nextest) need allow_leaving_process_group = true.
Each opt-out weakens the sandbox — see the details below.
Commands refuse to run at all, saying confinement isn’t available. The
kernel lacks Landlock (some older kernels, some WSL2 kernels). Set
require_enforcement = false under [sandbox] to run commands unconfined,
knowing what that gives up.
cargo build keeps failing in a project with a .env at its root.
Create the target/ folder once (mkdir target) — see “Directories holding
a denied entry” below.
An MCP server is skipped at start-up. It didn’t finish starting within
its timeout_secs. npx-based servers often need their cache directory
added to [sandbox] extra_read_paths, or use the server’s installed binary
directly. See MCP.
/commit says it can’t write the repository. You started aivyx-coder in
a subfolder of the repository or in a linked worktree; start it at the
repository root, or commit with git.
A container can’t reach a model server on the host. See Docker.
Known limitations
Deliberately not (yet) addressed — documented rather than hidden:
- Indirect prompt injection: content the agent reads (files, command
output, search results) re-enters the model’s context with no
trust/provenance tag — the model cannot structurally distinguish “the user
said X” from “a file said X.” The system prompt instructs the model to treat
such content as data, not instructions, but this is a mitigation, not a
guarantee. Be especially careful pointing the agent at untrusted repositories
while
allowed_commandsis configured — including, under--auto, the syntheticdetected-testsentry added automatically when no[verification] commandis set (see Autonomous and advanced modes) — since a pre-approved command runs without a per-invocation prompt. The heuristic injection scan (phrase-list matching over tool results as they re-enter context,aivyx-injection-guard) runs in every mode, on top of the mitigation above, but it’s a pattern-based heuristic, not a structural fix, and its response to a hit differs by mode. In interactive mode (the TUI, and editors via ACP) a hit surfaces as a passive notice after the turn — it doesn’t pause or block anything — because the permission modal (a human reviewing the actual command/diff before it executes) is already the primary mitigation there. Autonomous mode goes further precisely because there’s no human reviewing each prompt: it pauses the run outright on a high-confidence hit, and denies any further mutating or network tool call for the rest of that session until a human clears it. - Sandbox side effects you may hit (Linux confinement — see the security model):
-
No local daemons by default: ssh-agent, gpg signing,
docker, socket-based database clients and keyring-backed credential helpers fail inside confined commands unless[sandbox] allow_unix_sockets = true. -
Private
TMPDIR: commands get their own temp directory, one per confiner (the lead, each specialist session, each delegation), so a file a specialist leaves in$TMPDIRisn’t in yours, and it is gone once that specialist’s session or delegation ends. A tool that writes to a hard-coded/tmppath fails (share_system_tmp = trueto opt out). The lead’s is deleted when aivyx-coder exits normally (after a crash it’s left in the system temp dir asaivyx-confine-*). -
No listing above the project: a confined command can’t list directories outside the ones it’s granted, including
/,/tmpand the project’s parents. A tool that walks upward looking for a config file fails withPermission deniedon the first directory it can’t list. For example,just’s own test suite does this from temp directories, and fails confined inglobal::*,init::*andsearch::tests::not_found.extra_read_pathsdoesn’t help once the walk reaches/. List those tests in[verification] sandbox_failures(below), skip them in the configured test command (-- --skip global::), or run them yourself; granting read on/would expose every directory name on the machine. -
Tests that fail only in the sandbox: list them in
[verification] sandbox_failures, by name as the runner prints it or as a prefix ending in*:[verification] sandbox_failures = ["search::tests::not_found", "global::*", "init::*"]The model is told in its system prompt, and again under any test run where they fail, that these failures aren’t bugs and aren’t its task. A verification run whose only failures are on the list counts as passed (with a notice saying so), so
--autocan finish. Failures are read from cargo’s, pytest’s andgo test’s output; when the output can’t be read with confidence (another runner, a compile error, a crash, output cut short), nothing is excused. Unlike skipping a test, this needs no runner-specific flags and still runs the test. Ignored when commands don’t run sandboxed (a build without the sandbox), where those failures would be real. A test that hides the permission error it hit (just’ssearch::tests::not_found) looks like an ordinary bug otherwise: without the list, small models rewrite working code around it. -
The model is told when the sandbox may be the cause: every failed confined
run_command,run_shellor/testrun (and automatic verification, which uses them) ends with a short SANDBOX note: it ran in the sandbox, and if the failure could come from the restricted access, the model is to leave it failing and name it in its answer, not change code or tests to get around it. When the output also mentions a permission error (Permission denied,Operation not permitted,os error 13, …), a fuller note spells this out as numbered rules. The system prompt states the same rule. The short note is there because a test can swallow the real error:just’ssearch::tests::not_foundprints only “No justfile found error was expected”. Without these, models “fix” working code to get past the sandbox. Confined commands also seeAIVYX_CODER_SANDBOX=landlockin their environment. -
setsid/setpgidare blocked: test runners and supervisors that put children in their own process groups (cargo-nextest’s per-test process groups, Python’sstart_new_session=True, thesetsidtool, interactive job control) may fail;allow_leaving_process_group = trueopts out.git_commitand/commitrun git with-c maintenance.auto=false, so git doesn’t try to start its detached auto-maintenance (your own git still does it). Agit committhe model runs throughrun_shelldoes, and printsfatal: setsid failedwhile the commit itself succeeds. -
REPLs have no controlling terminal: a confined command already leads its own process group, and POSIX refuses
setsid()to a group leader, so a REPL started under the confiner can’t take the pty as its controlling terminal — whateverallow_leaving_process_groupsays. It gets noSIGWINCHon resize, and a Ctrl-C byte inrepl_senddoesn’t interrupt it (userepl_stop). -
Directories holding a denied entry: a directory that directly contains a
deny_pathsmatch (often the project root, for.env) gets list-and-create rights only.rm/mvof entries directly in it fail, and a file or directory created directly in it by a command can’t be written by that same command (echo a > new.txtleaves an empty file) — the next command can, so a retry usually works. Not forcargo build, though: cargo createstarget/by renaming a temp directory, which is never allowed there, so in a Rust project whose root holds a denied file (.envis denied by default) confined builds keep failing — and leave an undeletabletargetXXXXXXdirectory behind — untiltarget/exists. Create it once (mkdir target, confined or not) and builds work from then on. Deeper subdirectories are unaffected, and aivyx-coder’s own file tools (write_file,delete_file,move_file) aren’t confined. aivyx-coder prints a notice at startup when it sees a Rust project in this state. -
Rarer edges (details in aivyx-confine’s README, “Known limits”): when aivyx-coder runs in
$HOMEor an ancestor of it, a symlinked~/.cargo/~/.rustupis not granted (a command could have planted the link), so toolchains reached through one fail; and$HOMEgets stricter rules than a project: nothing can be created, deleted or renamed directly in~, dot files and folders (~/.bashrc,~/.config,~/.local),~/binand dotfiles linked from elsewhere are read-only, SSH/GPG keys, cloud and GitHub tokens, keyrings and browser profiles are unreadable, and folders above a linked dotfile folder accept no new entries. Visible folders (~/Projects) work as usual; run aivyx-coder in a project directory to avoid all of this. A working directory inside a denied directory gets no access at all; anextra_read_pathsentry inside the working directory that is a symlink grants nothing; a denied file nested about a thousand directories deep can exhaust a 1024-descriptor limit and every confined spawn is then refused (EMFILE); with basename-patterndeny_paths(.env,*.pem) every spawn rescans the working directory (cached by mtime, but noticeable on huge trees); aSOCK_DGRAMsocketpair()is refused along with Unix sockets; on a kernel whose Landlock ABI is older than 7 the newer restrictions (signal and abstract-socket scoping below ABI 6) simply aren’t enforced.
-
- Network is not restricted by the sandbox. A command you approve can make
network connections (needed for
cargo build,npm install,git clone, etc.). Combined with the read scope, an approved command could in principle exfiltrate anything in that scope. - Environment variables are inherited by spawned commands (needed by real
toolchains). A command like
envwill see whatever secrets are in your shell environment. This is standard for shell tools but worth knowing. - TOCTOU windows:
write_file/edit_file/read_file/patch_fileresolve their path once for the confirmation preview and again at execution; a symlink swapped in between could redirect the operation.deny_pathsand the Landlock scope still bound the blast radius. AIVYX_DEBUG_LOG: if you set this env var to capture raw wire traffic for debugging, it logs the full conversation (including file/command content) in plaintext, append-only, forever. The file is0600but has no rotation or expiry — treat it as sensitive and delete it when done.repl_start/repl_senduse a real pseudo-terminal (PTY), not plain pipes — a program run this way seesisatty()as true, so readline/history, color, and window-size-aware output all work as they would at a real terminal, and the pty resizes live asaivyx-coder’s own terminal does. Two consequences worth knowing, both deliberate: the pty’s default line discipline echoes input back before the program’s own response (matching what a human typing at a real terminal would see); and standard control characters inrepl_send’sinput(e.g. a literal Ctrl-C byte) are interpreted by the tty driver as signals to the process, not passed through as literal data — again, same as at a real terminal (except under the Linux sandbox, where the pty can’t be the REPL’s controlling terminal; see “Sandbox side effects you may hit” above).Tool::executebypass: the “all tool calls go through the permission gate” property is enforced by convention (the executor is the only caller), not by the type system.- Git specifics:
git_commit(re)stages the paths it commits, so a carefully staged partial hunk within those paths is staged in full (the modal preview shows the full scope first). Commit signing (GPG/SSH) and hooks that read paths outside the sandbox’s grants will fail under confinement.git_read’s status/diff excludedeny_pathsvia pathspecs, butlogshows committed history as-is — anything already committed is considered yours to see. move_filecross-filesystem moves: refused outright rather than transparently falling back to a recursive copy+delete, to keep the tool’s atomicity guarantee honest. In practice this only bites whenfrom/toresolve onto different mounted filesystems, which is rare for an in-project rename.