Clients can replace the current session's subprocess environment overrides using
SetSessionEnv (or the SDK's setSessionEnv / set_session_env helper). The map
replaces, rather than merges with, previous overrides. An empty map clears it.
Keys must be nonempty and contain neither = nor NUL, values cannot contain NUL,
and JCODE_* keys are reserved (case-insensitively).
These overrides apply to session-owned Bash subprocess launches, including queued background launches. Each accepted job keeps its own snapshot. Updating or clearing a session's map does not alter already accepted jobs or running processes. Overrides do not mutate the daemon's process environment. They are not a general override of provider authentication/configuration, shared MCP servers, or unrelated daemon services.
Forks, transfers, and swarm children receive independent copies of their parent's current overrides. Subsequent parent updates do not update existing children. Clearing conversation history carries overrides to the replacement session ID. Attaching an existing session uses that target's overrides, never the temporary connecting session's map. Session teardown removes the live registry entry, not environment copies already held by running jobs. Independent sessions do not receive another session's map.
Overrides are ephemeral and are explicitly lost on daemon restart or reload. They are not saved in session JSON, journals, reload recovery, or conversation history. Loading a saved session does not restore them. Clients must reapply overrides before submitting resumed work, including after reconnecting to a restarted daemon. Automatic recovery may run without them: this feature adds no fail-closed recovery barrier and must not be treated as one.
This is environment isolation, not a security sandbox or secret-redaction system. The registry does not intentionally log or persist values, but a command can print its environment into tool output, write it to disk, or transmit it elsewhere. Subprocesses inherit ordinary daemon environment variables unless overridden, and OS process inspection or another program running as the same user may expose secrets. Only supply credentials to trusted commands and trusted child agents.
SetSessionEnv also controls proxy routing for session-owned webfetch and all
local websearch engines: DuckDuckGo, Bing (HTML and API), SearXNG, custom HTTP
backends, and Kagi. This does not change API-key or endpoint resolution, which
still uses the existing tool configuration and daemon environment.
Recognized keys are HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and NO_PROXY, plus
their lowercase aliases. Each exact key resolves from the session first, then
the daemon environment. Reqwest's uppercase-first alias precedence is applied
after that layering. Consequently a lowercase session alias does not override an
inherited uppercase alias. Scheme-specific proxies take precedence over
ALL_PROXY. Empty scheme-specific values fall back to ALL_PROXY, while an
empty uppercase alias still masks its lowercase alias. NO_PROXY retains
reqwest's host/domain/IP/CIDR/wildcard matching. Setting only NO_PROXY preserves
the inherited proxies for other hosts. As in the current reqwest system matcher,
CGI mode (REQUEST_METHOD present) disables proxy routing.
No proxy keys, or clearing the session map, restores the original daemon-client
behavior. Otherwise each tool invocation selects immutable effective proxy
settings before making requests. Updates affect only new invocations, not an
in-flight response, redirects, or a search invocation's fallback engines. The
existing user agents, connection/pool settings, fetch timeout overrides, and
custom/Kagi redirect and timeout policies are preserved. Invalid proxy settings
fail closed with a redacted error, never silently retry via daemon credentials.
Reqwest's existing redirect authentication behavior is unchanged: a cross-host
plain-HTTP redirect strips Proxy-Authorization, although it keeps the selected
proxy route. HTTPS CONNECT authentication and same-host redirects retain the
selected proxy credentials. Proxies requiring authentication on every redirected
plain-HTTP hop may reject that cross-host hop.
Clients share connection pools by effective proxy configuration and HTTP policy, not session ID. The process-wide LRU holds at most 32 configurations/policies. Replacement, inheritance, clearing, and session teardown remove cached clients whose effective configuration is no longer referenced by any live session. In-flight client clones survive eviction and cleanup. Proxy cache debug output and transport errors do not expose proxy credentials or retain unsafe error source chains. The ephemeral environment registry is still not a sandbox.
Provider/model requests (including provider-native web search) and daemon-internal updates, telemetry, usage, authentication refresh, and catalogs remain on daemon configuration. OpenAI's raw WebSocket transport is unchanged and does not gain HTTP proxy support here. Remote HTTP/SSE MCP clients also remain daemon-scoped. Stdio MCP servers are shared/pool-scoped processes inheriting daemon environment, not per-session overrides. Do not use session credentials to configure shared MCP servers without a separate per-session transport/process isolation design.
The harness API supports a persistent compaction ceiling for each session:
{"v":1,"id":42,"req":"set_context_cap","session_id":"session-id","max_context_tokens":600000}The reply reports both the normalized override and the effective budget:
{"v":1,"reply_to":42,"ev":"context_cap_changed","session_id":"session-id","max_context_tokens":600000,"effective_budget":600000}The effective budget is the smaller of the model's context window and the session
ceiling. If no session ceiling is set, [compaction] max_context_tokens supplies
the ceiling instead. A global value of 0 means the model window is uncapped.
A session override replaces the global ceiling, so it can raise or lower it, but
can never exceed the model window.
Pass 0 or null to clear an override and return to the current global default.
Overrides are isolated between sessions, saved with the session, and restored on
resume after a daemon restart. Older sessions without this field inherit the
global default. Model changes recalculate the budget without discarding the
override.
Changes requested during a running turn wait for the session lock without blocking
the connection's request reader. Lowering the ceiling does not interrupt the
active request or immediately rewrite the transcript. Existing compaction
thresholds apply to subsequent requests. Use compact to request compaction
explicitly. The ceiling is a compaction budget, not an exact outbound token limit.
Rust SDK: client.set_context_cap(session_id, Some(600_000)).
TypeScript SDK: await client.setContextCap(sessionId, 600_000).
Both return the effective budget. Live token_usage events also carry an optional
effective_budget from the daemon, allowing clients to render a context meter
without treating the model's full window as the active compaction budget.
agentgrep is jcode's grep tool, built for agents. Matches include file structure, such as functions and their locations, so an agent can understand the surrounding code without reading an entire file. Results are adaptively trimmed based on what the agent has already seen to reduce repeated context.
See the agentgrep implementation.
Provider-side prompt caching lets repeated prompt prefixes reuse work from earlier requests. Jcode monitors provider-reported cache usage and compares request signatures to detect meaningful cache misses. The monitor runs inside the agent, so clients receive the same classified cache-miss events.
Cache reuse depends on the provider and the request. Monitoring makes misses visible rather than guaranteeing that every request will hit the cache.
See the KV cache monitor.
Define plans as phases → lanes → items, including plans with only one phase or lane:
{
"phases": [
{
"phase": 1,
"lanes": [
{
"lane": "implementation",
"items": [
{
"name": "Implement the change",
"description": "Implement and validate the requested behavior",
"status": "in_progress",
"priority": "high",
"confidence": "validated"
}
]
}
]
}
]
}Phases execute in declared order. Lanes within a phase can run in parallel, while items within a lane run in order. Items inherit phase and lane membership from their enclosing containers. Update existing items by name rather than resending the hierarchy. Names must be nonblank and globally unique across all phases and lanes. Use description for longer context and rename_to for an explicit rename, for example {"update":[{"name":"Implement the change","rename_to":"Implement the feature"}]}. Internal IDs are generated automatically and preserved when replacing a plan with the same task names. Legacy id/content/details calls remain accepted for compatibility. Flat saved todo lists remain compatible internally with storage, swarm coordination, and rendering.
A lane can optionally replace the default whole-prior-phase barrier with specific prerequisite task names from strictly earlier phases. For example, add this phase after the phase above:
{"phase": 2, "lanes": [{"lane": "tests", "after": ["Implement the change"], "items": [
{"name": "Test the change", "status": "pending", "priority": "high"}
]}]}The tests lane can start as soon as Implement the change is successfully completed, even
if an unrelated lane in phase 1 is still running. Omit after to retain the
phase barrier. When present, after must contain unique, existing task names and
must not be empty. remove, add.after, and update.lane_after also reference
task names. Ambiguous names in legacy saved lists are rejected rather than
selecting an arbitrary task. Saved items
carry this setting as lane_after. Cancelled or deleted prerequisites do not
satisfy the dependency. The TUI shows concise tests: after 1/1 · met
progress and does not dim a prerequisite-ready lane merely because its phase is
later. This note describes the prerequisite gate, not the lane's lifecycle or
other blockers.
No way forward.
completely_blocked is a condition on an unfinished todo, not another lifecycle status. Its object contains only a nonempty reason string explaining the blocker.
{
"update": [
{
"name": "Recover source data",
"completely_blocked": {
"reason": "Required source data no longer exists"
}
}
]
}The TUI labels this condition ✋ Completely blocked and shows the reason. Keep the todo pending or in progress. Automatic continuation skips that item without scheduling timed review reminders; independent work remains actionable. Clear the condition with "completely_blocked": null when a way forward exists, then reassess rather than assuming the task is complete.
An assigned worker's todo lane shares the opened session's live status renderer: activity spinner, observed input/output tokens, streaming throughput, connection, elapsed time, and current tool intent. Missing telemetry is not guessed from context size or lifetime totals. Waiting and stopped workers show their available reason instead of a live spinner. A completely blocked condition pauses its item without hiding independent work in the same lane.
Passive worker status is displayed with the todo lanes rather than in a second list beside the pinned todo band. Focused worker navigation and transcript controls remain available.
A hill-climbable task has a concrete objective and a repeatable way to measure progress. Instead of stopping at an assertion that the work is done, an agent can make a change, measure the result, and iterate against that feedback.
Jcode's todo assessments record the feedback loop, its coverage, how directly it tests the requested outcome, and the evidence for stopping. This distinguishes an implementation change from a validated user workflow.
See the todo tool implementation.