TeamCreate resolves maxConcurrentAgents from the per-team input, then
the maxConcurrentAgents setting, then unlimited (pre-fix behavior).
The cap is persisted in the manifest and registered on a process-wide
gate; agent threads still spawn immediately but block on an RAII slot
before entering their run loop, so manifest/task-claim semantics are
unchanged. TeamDelete forgets the gate so queued agents drain and no
stale team entries accumulate. Includes a gate regression test.
Review fixes for PR #3250:
1. Restore workspace-level unsafe_code = "forbid" (was downgraded to
"warn" for TUI support). The per-crate [lints.rust] unsafe_code =
"allow" on rusty-claude-cli already overrides it where needed.
2. Fix TaskClaim TOCTOU race in claim_task(). Replace exists()-then-write
with OpenOptions::create_new(true) which atomically fails if the lock
file already exists, eliminating the race window between the check and
the write.
3. Remove TUI scaffolding deps (ratatui, tui-textarea, gag, crossbeam-channel,
libc, unicode-width) and the /tui slash command spec — these belong in
a future TUI PR and are unused in the current source.
Also updates the provider chain precedence test to reflect the new behavior
where the caller's resolved model is the chain primary.
Co-Authored-By: Claw <noreply@openclaw.ai>
Port the agent-team enhancement layer onto upstream/main so the model
can spin up coordinated sub-agent teams for parallel work.
subagentModel config wiring (fix):
- Add subagent_model field to RuntimeFeatureConfig + RuntimeConfig::subagent_model()
accessor so the subagentModel setting (already validated by config_validate.rs)
is now actually read and stored.
- Agent tool's resolve_agent_model falls back to subagentModel from config
when no explicit model is passed.
Provider namespace separation:
- New 'custom-openai' provider kind with dedicated env vars
(CLAWCUSTOMOPENAI_API_KEY / CLAWCUSTOMOPENAI_BASE_URL)
- /setup wizard saves kind: 'custom-openai' for option 5
- Bare model name normalized to 'custom/' prefix to avoid proxy 404s
- Sub-agents inherit /setup-saved provider config via inject_config_as_env_fallbacks
Parallel tool execution:
- Override execute_batch to classify read-only tools as parallel-safe
and run them concurrently via std::thread::scope
- Results return in original model order
Team coordination layer:
- AgentMessage, TaskClaim, TeamStatus tools + shared mailbox directory
- Mode presets (tiny/1x ... mega/6x) + enriched TeamCreate/Agent descriptions
- Background team watcher
- /team slash command: on/off/status/toggle
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add selector field to ReadFileInput accepting GJC syntax (:50, :50-200, :50+150, :raw)
- Implement read_file_with_selector and read_file_in_workspace_with_selector
- Add apply_line_selector to parse and apply selectors to file contents
- Add truncation_footer field to ReadFileOutput for GJC-compatible output
- Add comprehensive tests for selector parsing and application through tool entry point
Selectors take precedence over offset/limit for backward compatibility.
Closes#3323
Two related gaps let a single agentic turn exceed a small context window,
with no recovery path once it happened.
1. read_file's character ceiling was a hardcoded 64 KB (~16k tokens), sized
for a 200k window. Two reads in one turn reach ~48k tokens, which a 32k
backend rejects outright. Make it configurable via CLAW_MAX_READ_CHARS,
defaulting to the existing 64 KB so behavior is unchanged unless set.
Reads remain paged, not refused: callers still get truncated/nextOffset.
2. Compaction could not help, because it works at message granularity and an
agentic turn is five messages (user / assistant+tool_use / tool_result /
assistant+tool_use / tool_result). With preserve_recent_messages: 4 the
only droppable message is the short user prompt, so the two oversized
tool results were preserved verbatim by design.
Trim preserved tool-result payloads over 16 KB to a head/tail excerpt with
an explicit "[... N characters elided ...]" marker, so the model knows its
view is partial and can re-read. Small payloads pass through untouched.
Also apply trimming on the early-return path: a session can exceed the
window while holding fewer messages than preserve_recent_messages, where
should_compact is false and message-granular compaction has no move to
make. compact_now no longer gates on removed_message_count alone, which
would have computed the smaller session and then discarded it.
Also fixes a pre-existing flaky test: repl_executes_python_code resolves the
python runtime through PATH, which the PowerShell tests blank while they run.
It now takes the same env_lock, so it no longer intermittently fails with
"python runtime not found" on a machine that has python.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bVvRYn7CQKR6hT2j1L6Cs
(cherry picked from commit b0d4d41e8132f8dc75717b1f74554d649639de10)
An unbounded read_file returned the entire file, which on a small-context
backend overflows the model's window. The backend then rejects the whole
request (llama-server: "request (N tokens) exceeds the available context
size"), which kills the turn — so reading everything at once is precisely
what makes the session stop. Observed live: one 100 KB source file is
~25k tokens against a 32k window with a ~6k-token prefix, and a session
read the same file three times and died on six 400s.
read_file now returns a page and says so:
- absent `limit` yields DEFAULT_READ_LINES (2000) rather than EOF
- MAX_READ_CHARS (64 KB) bounds the payload even when `limit` is
explicit, so minified or generated files can't defeat the line cap
- `truncated` and `nextOffset` tell the caller it has a partial view
and exactly where to resume; the tool description explains both
MAX_READ_SIZE (10 MB) is untouched: it is a process guard against slurping
huge or binary blobs, not a context guard, and at ~2.5M tokens it never
fires on the files that actually overflow a window.
Also clears pre-existing clippy failures in trident.rs that blocked
-D warnings on every edit to this crate.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9McEEH32ZtyM62GSXVSyJ
(cherry picked from commit c796d7e5eedc66b0cb37bb6823ec772f8ceef9cf)
feat: add persistent auto-memory system
Implement a file-based persistent memory system that allows the AI to retain knowledge about users, feedback, projects, and references across sessions.
## Implementation Details
- MemoryStore data layer with FNV-1a workspace fingerprinting
- MemoryRead/MemoryWrite tools with security hardening (path traversal, symlink, absolute path, and size limit protections)
- System prompt injection of MEMORY.md index with prompt injection mitigation (fenced code block + trust-lowering notice)
- autoMemoryEnabled config option (defaults to true)
- Doctor health check for auto-memory state
- /memory command enhancement showing persistent memory info
## Verification
✓ 1023 lib tests pass
✓ Output format contract tests pass
✓ Release build succeeds
✓ Security hardening verified
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Root knowledge base plus complexity-scored subdirectory files for the
rust/ workspace, its five highest-mass crates (runtime, rusty-claude-cli,
api, tools, commands, plugins), and the src/ Python porting workspace.
Generated via init-deep: 13 parallel explore agents, LSP/ast-grep code
map, centrality-scored placement. Snapshot in .omo/init-deep.json (local).
Close two ways the permission system could be bypassed:
- Workspace path traversal: normalize `.`/`..` lexically before the
boundary prefix comparison so paths like `/workspace/../../etc` can no
longer escape the sandbox. Fixed in both the runtime enforcer and the
duplicate check in the tools PowerShell path classifier.
- read-only mode no longer trusts the leading token alone: reject shell
metacharacters (chaining/substitution/redirect/pipe/subshell), drop
interpreters and build drivers (python/node/ruby/cargo/rustc) from the
allow-list, gate `git` to non-mutating subcommands, and reject `find`
actions that execute or delete.
Adds regression tests for both holes. The pre-existing, unrelated
worker_boot git-metadata test failure is not affected by this change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds aspect-rs AOP-style logging to execute_tool_with_enforcer, providing cross-cutting arg/result logging for all tool dispatches. Introduces aspect-core, aspect-macros, and aspect-std dependencies.
Resolve the G012 evidence gate by fixing permission-mode regressions, platform-sensitive tests, and the clippy surface that blocked an all-targets verification run.
Constraint: G012 final gate required docs, board, full workspace tests, and clippy -D warnings evidence before checkpointing.
Rejected: documenting the worker-2 gate failure as an accepted gap | the failing tests and lints were locally reproducible and fixable.
Confidence: high
Scope-risk: moderate
Directive: Preserve read-only permission requirements for read/glob/grep tools; write/edit remain workspace-write or danger-full-access when outside the workspace.
Tested: python3 .github/scripts/check_doc_source_of_truth.py; python3 .github/scripts/check_release_readiness.py; python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json; python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json; cargo fmt --manifest-path rust/Cargo.toml --all -- --check; cargo check --manifest-path rust/Cargo.toml --workspace; cargo test --manifest-path rust/Cargo.toml --workspace -- --nocapture; cargo clippy --manifest-path rust/Cargo.toml --workspace --all-targets -- -D warnings
Not-tested: live network provider smoke tests and remote PR/issue mutations.
Canonicalize absolute shell path operands before comparing them with the workspace root so symlink-expanded reads cannot be downgraded under workspace-write enforcement. Also resolves local clippy findings in the touched tools crate so targeted linting can run cleanly.\n\nConstraint: Task 1 scope is workspace/path scope enforcement only; do not mutate .omx/ultragoal.\nRejected: Editing shared path-scope regression tests | worker-3 owns that test coverage and the current tests already prove the contract.\nConfidence: high\nScope-risk: narrow\nDirective: Keep shell/file permission classification canonical-path based before permitting workspace-write execution.\nTested: ../scripts/fmt.sh --check; cargo test -p tools --test path_scope_enforcement -- --nocapture; cargo test -p tools given_workspace_write_enforcer_when_bash -- --nocapture; cargo check -p tools; cargo clippy -p tools --all-targets --no-deps -- -D warnings\nNot-tested: Full workspace clippy still has known unrelated runtime crate warnings outside this task scope.
Worker-3's path-scope regression showed outside read_file paths were blocked by the workspace wrapper after dispatch instead of by the permission enforcer. File, glob, and grep tools now classify path scope before dispatch and require danger-full-access for paths that resolve outside the current workspace.
Constraint: G002-alpha-security requires permission-mode event/status visibility for blocked file and shell paths
Rejected: relying only on runtime wrapper errors | it hides the active permission-mode denial contract from callers
Confidence: high
Scope-risk: narrow
Directive: keep path-sensitive tool permission classification aligned with workspace wrapper resolution
Tested: cargo test -p tools --test path_scope_enforcement --manifest-path rust/Cargo.toml --quiet; cargo test -p tools given_workspace_write_enforcer_when_bash --manifest-path rust/Cargo.toml --quiet; cargo check --manifest-path rust/Cargo.toml --workspace; cargo fmt --all --manifest-path rust/Cargo.toml -- --check
Not-tested: full workspace test suite after this small permission-classification follow-up
Co-authored-by: OmX <omx@oh-my-codex.dev>
Constraint: G002-alpha-security requires direct file-tool escapes to fail before reads while accepting the canonical runtime error text.
Rejected: weakening the test to accept successful reads | the verified behavior denies the escape and only the assertion vocabulary was stale.
Confidence: high
Scope-risk: narrow
Directive: Keep path-scope tests asserting denial semantics, not a single legacy wording.
Tested: cargo fmt --manifest-path rust/Cargo.toml --all -- --check; cargo test --manifest-path rust/Cargo.toml -p tools path_scope -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools --test path_scope_enforcement -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime workspace_ -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --test output_format_contract -- --nocapture; python3 -m pytest tests/test_security_scope.py -q; cargo check --manifest-path rust/Cargo.toml --workspace; git diff --check
Not-tested: full cargo test --workspace due known unrelated session_lifecycle_prefers_running_process_over_idle_shell failure.
Co-authored-by: OmX <omx@oh-my-codex.dev>
The G002 security gate caught that PowerShell path classification still treated Windows absolute paths as workspace-relative on POSIX, so workspace scope now rejects those tokens before permission downgrades.
Constraint: G002-alpha-security requires workspace/path scope across Windows path cases as well as direct paths, symlinks, globbing, shell expansion, and worktrees.
Rejected: Relying on PathBuf::is_absolute for Windows syntax on POSIX | it treats C:\ and UNC-like tokens as relative and weakens permission classification.
Confidence: high
Scope-risk: narrow
Directive: Keep bash and PowerShell path classifiers aligned whenever new shell syntax is admitted.
Tested: cargo test --manifest-path rust/Cargo.toml -p tools path_scope -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p tools --test path_scope_enforcement -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p runtime workspace_ -- --nocapture; python3 -m pytest tests/test_security_scope.py -q; cargo check --manifest-path rust/Cargo.toml --workspace.
Not-tested: Full cargo test --workspace still has existing unrelated rusty-claude-cli session lifecycle failure reported by workers.
Co-authored-by: OmX <omx@oh-my-codex.dev>
Cherry-pick from Yeachan-Heo's #2945 with manual conflict resolution:
- classify_skills_slash_command now catches -h/--help anywhere in args
- Restored pending_thinking parameter in push_output_block test calls
Co-authored-by: Yeachan-Heo <bellman@ultraworkers.dev>
Five interrelated fixes from parallel Hephaestus sessions:
1. fix(repl): display assistant text after spinner (#2981, #2982, #2937)
- Added final_assistant_text() call after run_turn spinner completes
- REPL now shows response text like run_prompt_json does
2. fix(compact): handle Thinking content blocks (#2985)
- Added ContentBlock::Thinking variant throughout compact summarizer
- Prevents panic when /compact encounters thinking blocks
3. fix(prompt): provider-aware model identity (#2822)
- New ModelFamilyIdentity enum (Claude vs Generic)
- Non-Anthropic models no longer say 'I am Claude'
- model_family_identity_for() detects provider and sets identity
4. fix(openai): preserve DeepSeek reasoning_content (#2821)
- Stream parser now captures reasoning_content from OpenAI-compat
- Emits ThinkingDelta/SignatureDelta events for reasoning models
- Thinking blocks included in conversation history for re-send
5. feat(runtime): Thinking block support across codebase
- AssistantEvent::Thinking variant in conversation.rs
- ContentBlock::Thinking in session serialization
- Thinking-aware compact summarization
- Tests for thinking block ordering and content
Closes#2981, #2982, #2937, #2985, #2822, #2821
Reject empty --allowedTools inputs instead of treating them as an empty restriction, and surface status JSON metadata that distinguishes default unrestricted tools from flag-provided allow lists.
Confidence: high
Scope-risk: narrow
Tested: cargo test -p rusty-claude-cli rejects_empty_allowed_tools_flag -- --nocapture
Tested: cargo test -p tools allowed_tools_rejects_empty_token_lists -- --nocapture
Tested: cargo check -p rusty-claude-cli -p tools
Tested: cargo test -p rusty-claude-cli -p tools
Not-tested: full workspace cargo fmt --check is blocked by pre-existing unrelated formatting drift
Recent OMX dogfooding kept surfacing raw `[OMX_TMUX_INJECT]`
messages as lane results, which told operators that tmux reinjection
happened but not why or what lane/state it applied to. The lane-finished
persistence path now recognizes that control prose, stores structured
recovery metadata, and emits a human-meaningful fallback summary instead
of preserving the raw marker as the primary result.
Constraint: Keep the fix in the existing lane-finished metadata surface rather than inventing a new runtime channel
Rejected: Treat all reinjection prose as ordinary quality-floor mush | loses the recovery cause and target lane operators actually need
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Recovery classification is heuristic; extend the parser only when new operator phrasing shows up in real dogfood evidence
Tested: cargo fmt --all --check
Tested: cargo clippy --workspace --all-targets -- -D warnings
Tested: cargo test --workspace
Tested: LSP diagnostics on rust/crates/tools/src/lib.rs (0 errors)
Tested: Architect review (APPROVE)
Not-tested: Additional reinjection phrasings beyond the currently observed `[OMX_TMUX_INJECT]` / current-mode-state variants
Related: ROADMAP #68
The repo-local backlog was effectively exhausted, so this sweep promoted the
newly observed test-lock poisoning pain point into ROADMAP #74 and fixed it in
place. Test-only env/cwd lock acquisition now recovers poisoned mutexes in the
remaining strict call sites, and each affected surface has a regression that
proves a panic no longer permanently poisons later tests.
Constraint: Keep the fix test-only and avoid widening runtime behavior changes
Rejected: Refactor shared helper signatures across broader call paths | unnecessary churn beyond the remaining strict test sites
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: These guards only recover the mutex; tests that mutate env or cwd still must restore process-global state explicitly
Tested: cargo fmt --all --check
Tested: cargo clippy --workspace --all-targets -- -D warnings
Tested: cargo test --workspace
Tested: Architect review (APPROVE)
Not-tested: Additional fault-injection around partially restored env/cwd state after panic
Related: ROADMAP #74
The next repo-local sweep target was ROADMAP #66: reminder/cron
state could stay enabled after the associated lane had already
finished, which left stale nudges firing into completed work. The
fix teaches successful lane persistence to disable matching enabled
cron entries and record which reminder ids were shut down on the
finished event.
Constraint: Preserve existing cron/task registries and add the shutdown behavior only on the successful lane-finished path
Rejected: Add a separate reminder-cleanup command that operators must remember to run | leaves the completion leak unfixed at the source
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If cron-matching heuristics change later, update `disable_matching_crons`, its regression, and the ROADMAP closeout together
Tested: cargo fmt --all --check; cargo clippy --workspace --all-targets -- -D warnings; cargo test --workspace; architect review APPROVE
Not-tested: Cross-process cron/reminder persistence beyond the in-memory registry used in this repo
The next repo-local sweep target was ROADMAP #64: downstream consumers
still had to infer artifact provenance from prose even though the repo
already emitted structured lane events. The fix extends `lane.finished`
metadata with structured artifact provenance so successful completions
can report roadmap ids, files, diff stat, verification state, and commit
sha without relying on narration alone.
Constraint: Preserve the existing commit-created event and lane-finished metadata paths while adding structured provenance to successful completions
Rejected: Introduce a separate artifact event type first | unnecessary for this focused closeout because `lane.finished` already carries structured data and existing consumers can read it there
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If artifact provenance extraction rules change later, update `extract_artifact_provenance`, its regression payload, and the ROADMAP closeout together
Tested: cargo fmt --all --check; cargo clippy --workspace --all-targets -- -D warnings; cargo test --workspace; architect review APPROVE
Not-tested: Downstream consumers that ignore `lane.finished.data.artifactProvenance` and still parse only prose output