feat(site): refresh aegntic.ai company website#29
Conversation
…ation - Added trace_id field to AgentEntry and Session structs - Added trace_context.rs module for task-local TraceId storage - Added openclaw.rs with canonical types for OpenClaw HTTP proxy routes - Added docker-compose.openclaw.yml for service orchestration - Added PostgreSQL schema with seed data - All 279 tests pass - Build compiles - Clippy passes with zero warnings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…oof, gitignore updates - Fix clippy lints: use #[default] derive for GoalStatus, IssueStatus, AgentKind - Remove redundant Default impls in company.rs and openclaw.rs - Fix unnecessary clone in trace_context.rs - Allow clippy::items_after_test_module in tui/mod.rs - Reformat re-exports in types/lib.rs and route formatting in routes.rs - Add bun/bunx fallback to dashboard-proof.sh (no longer requires npx) - Relax dashboard-proof version check to title+agents-panel assertion - Add .worktrees/, .swarm/, output/demo/ to .gitignore
- Extract is_loopback_request(), is_public_dashboard_path() helpers
- Add loopback-only bypass for Obsidian bootstrap routes (POST /api/agents,
GET/PUT /api/agents/{id}/files/*) so the local dashboard can seed and
sync memory files without forcing an auth prompt
- Add tests for bootstrap bypass (loopback allowed, remote rejected,
unrelated routes rejected)
Environments without local TCP listener support (sandboxed CI, containers) now skip gracefully instead of failing. Adds the guard macro to all tests in api_integration_test, daemon_lifecycle_test, load_test, and wire/peer.
OpenClaw integration: - Add openclaw.rs module proxying to local OpenClaw Docker services (registry, dispatcher, scheduler, evaluator, repair) - Register 13 new /api/openclaw/* routes in server.rs - Add reqwest + lazy_static dependencies for HTTP proxying Auto-import system: - Add auto_import.rs module for scanning local directories to discover MCP servers, skills, and plugins - Register /api/import/scan, /api/import, /api/import/suggestions routes - Add import.js page (scan UI, item selection, import flow) - Add model-selector.js page (rich model browsing with tier/provider filters) - Wire both JS pages into webchat.rs SPA bundle
…PI error fix button Skills page: - Rework installed skills to compact list view with inline remove - Add Local tab for scanning and importing skills from local directories - Improve empty state with structured onboarding options (ClawHub, Local, Build) Settings/Models: - Add model tier filter presets (Frontier, Smart, Fast, Local) - Add available-only toggle for model catalog - Add Import tab for settings page Chat: - Add 'Fix API Configuration' button on system error messages (401/403/API errors) Styles: - Add skill-list, skill-row, model-preset-btn component styles to components.css - Extend app.js with local skill scanning and import helpers
…sion restore archives - Add 16 launch task specs (docs/launch-tasks/0-15) defining the parallel public alpha launch plan with dependencies, proof rules, and worktree conventions - Add metallic design baseline (docs/design/launch-metallic-baseline.md) - Add cli-swarm orchestration scripts (launch.py, launch_live_windows.py, verify.sh, proof-demo.sh, status.py) for multi-agent kitty/tmux coordination - Add session restore snapshot (2026-03-13-launch-alpha) preserving the launch alpha planning session state, prompts, and conversation context - Add cli-swarm overview doc (docs/cli-swarm.md)
- Modern hero section with "AI Agents That Evolve" headline - Services grid: Custom Agent Development, AI Infrastructure, Consulting & Integration, Self-Modifying Systems - Product showcase for ClawReform with feature list and code block - Case studies: DevOps (80% reduction), Security (24/7), Data (Auto) - Tech stack badges: Rust Core, Tailscale Mesh, MCP Protocol, A2A - Dark/light theme toggle with glassmorphism design - Mobile responsive with scroll reveal animations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @aegntic, your pull request is larger than the review limit of 150000 diff characters
📝 WalkthroughWalkthroughThis PR introduces significant infrastructure for OpenClaw multi-service orchestration, auto-import capabilities for MCP servers and skills, trace context management, comprehensive UI enhancements, and extensive launch automation tooling. It spans backend APIs, frontend pages, type definitions, testing utilities, Docker deployment, and launch task documentation. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User/Browser
participant WebUI as ClawREFORM Web UI
participant API as clawreform-api
participant AutoImport as Auto-Import Module
participant FS as Local Filesystem
participant OpenClaw as OpenClaw Services
participant Registry as Registry Service
User->>WebUI: Click "Find Local Skills"
WebUI->>API: POST /api/import/suggestions
API->>AutoImport: get_suggestions()
AutoImport->>API: Return suggested directories
API->>WebUI: Suggestion list
User->>WebUI: Select directory & scan
WebUI->>API: POST /api/import/scan {directory}
API->>AutoImport: scan_directory()
AutoImport->>FS: Traverse directories recursively
AutoImport->>AutoImport: Classify items by manifest patterns
FS->>AutoImport: Item metadata (descriptions, versions)
AutoImport->>API: Discovered items grouped by type
API->>WebUI: Skills/MCP servers/Plugins list
User->>WebUI: Select items & import
WebUI->>API: POST /api/import {selected items}
API->>AutoImport: import_items()
AutoImport->>AutoImport: Dispatch by item_type
alt Skill Import
AutoImport->>FS: Copy skill source to skills home
AutoImport->>API: Reload skill registry
else MCP Server/Plugin
AutoImport->>API: Log & acknowledge (future expansion)
end
AutoImport->>API: Import results {imported, failed, status}
API->>WebUI: Update discovered items & refresh lists
WebUI->>User: Success toast & updated UI
sequenceDiagram
participant CLI as Launch Script
participant Worktree as Git Worktree
participant Tmux as Tmux Session
participant Window as Kitty Window
participant Agent as Task Agent (CLI)
participant API as clawreform-api
CLI->>Worktree: Create linked worktree for task
Worktree->>Worktree: Checkout task-specific branch
CLI->>Worktree: Sync bootstrap docs & prompts
Worktree->>Worktree: Copy launch-tasks, baseline design
CLI->>Tmux: Create tmux session
Tmux->>Agent: Start agent with environment
Agent->>API: Execute task (scan, import, etc.)
API->>Agent: Return results
Agent->>Worktree: Write artifacts to output/
CLI->>Window: Generate kitty session file
Window->>Tmux: Attach window to session
Window->>Agent: Display live agent output
Agent->>Window: Print logs & progress
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes This PR introduces extensive heterogeneous changes across the entire codebase: new backend services (auto-import, OpenClaw proxying), comprehensive frontend pages with complex JavaScript state management, new type system foundations (trace context, OpenClaw schemas), Docker deployment infrastructure, sophisticated orchestration tooling with multi-language scripts, and extensive launch automation documentation. The changes span authentication middleware, API routing, UI components, CSS systems, JavaScript state management, Rust type definitions, database schema, containerization, and bash/Python scripting. While many individual cohorts are straightforward (ballast trace_id additions, test macro applications), the overall scope demands careful review of interconnections, particularly between the new API endpoints, frontend integration, database schema design, and the launch automation framework. Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 11
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
scripts/dashboard-proof.sh (1)
18-35:⚠️ Potential issue | 🟠 MajorSubpath deployments break the health check.
base_url()strips everything after the origin, but Line 83 always probes${BASE_URL}/api/health. A URL likehttps://host/app/#agentswill therefore curlhttps://host/api/health, so the proof fails before the browser step even starts. Make the health endpoint prefix-aware or at least overridable.🩹 Minimal fix
BASE_URL="$(base_url "${URL}")" +HEALTH_URL="${DASHBOARD_HEALTH_URL:-${BASE_URL}/api/health}" @@ -HEALTH_JSON="$(curl -fsS "${BASE_URL}/api/health")" +HEALTH_JSON="$(curl -fsS "${HEALTH_URL}")"Also applies to: 83-83
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/dashboard-proof.sh` around lines 18 - 35, The health check breaks for subpath deployments because base_url() currently returns only the origin and the script always probes "${BASE_URL}/api/health"; update base_url() or the health probe to preserve the URL path (strip fragment/query but keep the path) or make the health path overridable. Concretely, change base_url() (and where BASE_URL is set) so it returns origin+path (no fragment/query) or add a HEALTH_ENDPOINT/HEALTH_PATH env variable and compute HEALTH_URL from BASE_URL plus the preserved path, then use that HEALTH_URL instead of "${BASE_URL}/api/health" in the health probe commands to ensure subpath deployments like "https://host/app/#agents" probe "https://host/app/api/health" (reference functions/vars: base_url(), BASE_URL and the health probe usage of "${BASE_URL}/api/health").crates/clawreform-api/src/routes.rs (1)
9125-9139:⚠️ Potential issue | 🟠 MajorDon’t swallow persistence failures in the shared save helper.
structured_setcan fail, but this helper drops the error. That means/api/company/...mutations can return 200/201 even when nothing was persisted, which turns storage issues into silent data loss.🛠️ Suggested direction
-fn save_company_entries<T>(state: &AppState, key: &str, entries: &[T]) +fn save_company_entries<T>(state: &AppState, key: &str, entries: &[T]) -> Result<(), String> where T: serde::Serialize, { let payload = match serde_json::to_value(entries) { Ok(value) => value, Err(error) => { tracing::warn!("Failed to serialize {key} entries: {error}"); - return; + return Err(format!("Failed to serialize {key} entries: {error}")); } }; - let _ = state + state .kernel .memory - .structured_set(*COMPANY_AGENT_ID, key, payload); + .structured_set(*COMPANY_AGENT_ID, key, payload) + .map_err(|error| format!("Failed to persist {key} entries: {error}")) }Then have the company mutation handlers convert that
Errinto a 5xx instead of reporting success.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-api/src/routes.rs` around lines 9125 - 9139, save_company_entries currently swallows errors from state.kernel.memory.structured_set; change it to return a Result (e.g., Result<(), E> or anyhow::Error) instead of void, propagate the serde_json::to_value error as Err and return the Err from the structured_set call (referencing save_company_entries, structured_set, COMPANY_AGENT_ID, and AppState), and update the company mutation handlers that call save_company_entries to map any Err into a 5xx response instead of reporting success so persistence failures surface to clients.
🟠 Major comments (27)
site/index.html-651-653 (1)
651-653:⚠️ Potential issue | 🟠 MajorMobile navigation is removed without an alternative path.
Line 652 hides
.nav-linkson small screens, but no mobile menu/toggle is provided around Line 716-721. This removes direct section navigation on mobile.Also applies to: 716-721
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@site/index.html` around lines 651 - 653, The CSS rule hiding `.nav-links` on small screens removes access to navigation; restore mobile navigation by adding a visible toggle and a show-state for `.nav-links`: introduce a `.mobile-nav-toggle` control (button/icon) and a CSS state such as `.nav-open .nav-links` or `.nav-links.open` that displays the menu when active, and wire a small JS handler (e.g., a click listener on `.mobile-nav-toggle`) to toggle the `nav-open` class on a container (header or body) or toggle `.open` on `.nav-links`; update accessibility attributes (aria-expanded) on the toggle and ensure the existing `.nav-links` selector is used for the show/hide behavior so navigation works on mobile (refer to `.nav-links`, `.mobile-nav-toggle`, and the `.nav-open` or `.open` state).site/index.html-634-643 (1)
634-643:⚠️ Potential issue | 🟠 MajorCore content is hidden when JS/observer is unavailable.
Line 634 hides all
.revealelements by default, and they only become visible through JS at Line 1028-1042. If JS is blocked/fails, large sections remain invisible.Suggested fix (progressive enhancement)
-.reveal { - opacity: 0; - transform: translateY(30px); - transition: opacity 0.6s ease, transform 0.6s ease; -} - -.reveal.visible { +.reveal { opacity: 1; transform: translateY(0); } + +.js .reveal { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.js .reveal.visible { + opacity: 1; + transform: translateY(0); +}<script> + document.documentElement.classList.add('js'); // Theme Toggle function toggleTheme() {Also applies to: 1028-1042
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@site/index.html` around lines 634 - 643, The CSS currently hides all .reveal elements by default which breaks content when JS/observer fails; change to progressive enhancement by making .reveal visible by default and only hide them when JS is enabled: add a top-level marker class (e.g., "js-enabled") on document.documentElement from your initialization JS (the code that currently sets up the observer), move the initial hidden styles into .js-enabled .reveal { opacity:0; transform:translateY(30px); transition:... } and keep .js-enabled .reveal.visible { opacity:1; transform:translateY(0); } so content is accessible without JS and the existing observer logic can continue to toggle the .visible class as before.site/index.html-715-715 (1)
715-715:⚠️ Potential issue | 🟠 MajorLogo link
href="#"throws an invalid selector error and breaks navigation.Line 715 contains
href="#", and the click handler at Line 1048 passes this todocument.querySelector(), which throws aDOMExceptionbecause"#"is not a valid CSS selector. This prevents the logo from functioning as intended.Suggested fix
document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { - e.preventDefault(); - const target = document.querySelector(this.getAttribute('href')); + const href = this.getAttribute('href'); + if (!href || href === '#') return; + const target = document.querySelector(href); if (target) { + e.preventDefault(); target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@site/index.html` at line 715, The logo anchor uses href="#" which is passed to document.querySelector() and causes a DOMException; update the anchor (class="logo") to use a valid selector/value (for example href="#top" or a data-target attribute) or change the click handler that calls document.querySelector() to guard/normalize the href (e.g., ignore or map "#" to a valid selector before calling document.querySelector()). Ensure you update the code paths that read the anchor's href (the click handler using document.querySelector) so they never pass the raw "#" string to document.querySelector().docs/design/launch-metallic-baseline.md-5-11 (1)
5-11:⚠️ Potential issue | 🟠 MajorCommit the reference boards or link them from a shared location.
The
/home/ae/Downloads/...paths and “current planning thread” only exist for the author, so other contributors cannot reconstruct this baseline from the repo. Check the boards into version control or replace them with shared relative links.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/design/launch-metallic-baseline.md` around lines 5 - 11, The markdown lists local-only image references (e.g., 1_clawREFORM_design_z-axis.png, 2_clawREFORM_design_debossed.png, 4_clawREFORM_design_layeringmetals.png, 7_clawREFORM_design_lightspill.png and “attached concept boards”) that others cannot access; commit those reference boards into the repository (e.g., docs/design/assets/) or upload them to a shared location and replace the local paths in launch-metallic-baseline.md with stable relative repo paths or canonical shared URLs, and update the document’s bullet list to point to those committed asset filenames or links so others can reconstruct the baseline.scripts/cli-swarm/proof-demo.sh-19-30 (1)
19-30:⚠️ Potential issue | 🟠 MajorDon't leave the rendered MP4 in an unignored repo folder.
Lines 19-29 create
demo/clawreform-remotion.mp4, copy it tooutput/demo/, and never clean the original. Running the proof script will dirty the worktree with a large generated binary even thoughoutput/demo/is already the intended artifact location.🧹 Minimal cleanup
if [[ -f "${ROOT_DIR}/demo/clawreform-remotion.mp4" ]]; then cp "${ROOT_DIR}/demo/clawreform-remotion.mp4" "${VIDEO_OUT}" + rm -f "${ROOT_DIR}/demo/clawreform-remotion.mp4" + rmdir "${ROOT_DIR}/demo" 2>/dev/null || true fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/cli-swarm/proof-demo.sh` around lines 19 - 30, The script currently renders into "${ROOT_DIR}/demo/clawreform-remotion.mp4" and copies it to "${VIDEO_OUT}" but leaves the large binary in the repo demo folder; modify the flow in the proof-demo.sh script (look for the block using ROOT_DIR, REMOTION_DIR, and VIDEO_OUT and the demo/clawreform-remotion.mp4 path) so the artifact is not left behind — either render directly to "${VIDEO_OUT}" (pass that path into the render command) or, if rendering must target "${ROOT_DIR}/demo", remove the source file after a successful cp (check existence, cp to VIDEO_OUT, then rm "${ROOT_DIR}/demo/clawreform-remotion.mp4"); ensure error handling preserves the copy if rm fails.docs/launch-tasks/14_clawREFORM_design-system-translation.md-37-37 (1)
37-37:⚠️ Potential issue | 🟠 MajorUse a repo-relative baseline link here.
Line 37 points to
/home/ae/clawreform/..., which only resolves on one workstation and breaks rendered docs. The prompt chain should reference the checked-in baseline relatively and the image pack from a shared location.✏️ Suggested edit
-1. Read [launch-metallic-baseline.md](/home/ae/clawreform/docs/design/launch-metallic-baseline.md) and the referenced local image pack. Distill real design tokens for depth, shadow, bevel, glow, and type. +1. Read [launch-metallic-baseline.md](../design/launch-metallic-baseline.md) and the shared image pack. Distill real design tokens for depth, shadow, bevel, glow, and type.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/launch-tasks/14_clawREFORM_design-system-translation.md` at line 37, The markdown contains an absolute workstation link to launch-metallic-baseline.md; replace that absolute /home/... target (the link target for launch-metallic-baseline.md) with a repo-relative link to the checked-in baseline file and update the referenced image pack link to a shared repo-relative location so the docs render correctly for all contributors.docs/session-restore/2026-03-13-launch-alpha/launch-tasks/12_clawREFORM_email-list-super-sherlock.md-19-24 (1)
19-24:⚠️ Potential issue | 🟠 MajorAdd explicit email compliance constraints.
The scope and prompt chain currently omit consent/unsubscribe/compliance requirements. That creates legal/privacy risk when this plan is executed.
Suggested additions
## Scope - lead source map - segmentation - launch email sequence - high-priority outreach targets - follow-up logic +- consent/opt-in status and suppression rules +- unsubscribe language and CAN-SPAM/GDPR compliance checks ## Prompt Chain 1. Build the email intelligence model for launch. Define likely lead sources, segments, scoring, and priority outreach logic in `lead-source-map.md` and `segmentation-model.md`. -2. Write the launch email sequence: announcement, reminder, proof follow-up, and design-partner outreach. +2. Write the launch email sequence: announcement, reminder, proof follow-up, and design-partner outreach, including compliant footer/unsubscribe handling. 3. Leave a sherlock-style note in `handoff.md` that explains who deserves immediate attention after launch and why.Also applies to: 40-42
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/launch-tasks/12_clawREFORM_email-list-super-sherlock.md` around lines 19 - 24, Update the plan to include explicit email compliance constraints tied to the listed items: for "launch email sequence", "follow-up logic", "high-priority outreach targets", "lead source map", and "segmentation" specify required consent (documented opt-in or double opt-in), mandatory unsubscribe/opt-out footer and functioning one-click unsubscribe link in all templates, suppression-list enforcement (global unsubscribe, bounces, spam complaints) before sends, retention of consent and suppression audit logs, honoring jurisdictional rules (e.g., CAN-SPAM, GDPR) including data subject rights and opt-out processing times, and a requirement that any sending pipeline or automation (the sequence/follow-up workflow) checks the suppression/consent store and rate-limits sends to avoid harassment or throttling issues.docs/session-restore/2026-03-13-launch-alpha/state/visible-launch-manifest.json-3-87 (1)
3-87:⚠️ Potential issue | 🟠 MajorHardcoded absolute paths make the restore manifest non-portable.
Lines 3-87 lock the manifest to
/home/ae/..., so restores fail on different machines and leak local directory layout in-repo.🔧 Proposed direction (representative)
{ "run_name": "launch-alpha", - "session_file": "/home/ae/clawreform/.swarm/launch-alpha/kitty-live.session", + "session_file": ".swarm/launch-alpha/kitty-live.session", "tasks": [ { "task_id": "1", - "worktree": "/home/ae/clawreform/.worktrees/01-pre-site-deployment", - "artifact_dir": "/home/ae/clawreform/.worktrees/01-pre-site-deployment/output/launch/01-pre-site-deployment", + "worktree": ".worktrees/01-pre-site-deployment", + "artifact_dir": ".worktrees/01-pre-site-deployment/output/launch/01-pre-site-deployment", ... } ] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/state/visible-launch-manifest.json` around lines 3 - 87, The manifest currently contains hardcoded /home/ae/... absolute paths (see keys like "session_file", each task's "worktree", "artifact_dir", "prompt_file", "log_file" and the embedded paths in "screen_command" and "agent_command"), making restores non‑portable; update the manifest to use relative paths or templated placeholders (e.g. ${WORKTREE_ROOT} or ${REPO_ROOT} and ${AGENT_BIN}) instead of /home/ae, and change each task entry (tasks[].worktree, tasks[].artifact_dir, tasks[].prompt_file, tasks[].log_file, tasks[].screen_command, tasks[].agent_command and top‑level session_file) to reference those templates so a restore script can substitute local values at runtime (or compute absolute paths from the repo root), then adjust any restore/launcher code that reads visible-launch-manifest.json to perform the substitution/resolution before launching.docs/session-restore/2026-03-13-launch-alpha/launch-tasks/2_clawREFORM_audit_dl-path.md-10-10 (1)
10-10:⚠️ Potential issue | 🟠 MajorAlign this task’s worktree location with
.worktrees/.
Line 10points to../clawreform-launch-02-audit-dl-path, which conflicts with the documented.worktrees/...launch flow used bylaunch_live_windows.py. Please standardize to avoid task bootstrap failures.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/launch-tasks/2_clawREFORM_audit_dl-path.md` at line 10, The worktree path string "../clawreform-launch-02-audit-dl-path" in the document should be changed to the standardized .worktrees location to match launch_live_windows.py; locate the line containing the literal "../clawreform-launch-02-audit-dl-path" and replace it with ".worktrees/clawreform-launch-02-audit-dl-path" (or the appropriate subdirectory under .worktrees/) so the task bootstrap uses the documented .worktrees/... flow.docs/session-restore/2026-03-13-launch-alpha/launch-tasks/8_clawREFORM_youtube-launch-automation.md-10-10 (1)
10-10:⚠️ Potential issue | 🟠 MajorStandardize task paths to prevent operator drift.
Line 10uses../clawreform-launch-...instead of the documented.worktrees/...pattern, andLine 46uses a machine-local absolute doc path. Both should be normalized to repo-portable paths.Also applies to: 46-46
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/launch-tasks/8_clawREFORM_youtube-launch-automation.md` at line 10, Replace the hardcoded worktree and machine-local absolute doc paths with repo-portable relative paths: change the Worktree value that currently reads "../clawreform-launch-08-youtube-launch-automation" (referenced at Line 10) to the standardized ".worktrees/clawreform-launch-08-youtube-launch-automation" pattern, and update the absolute documentation path referenced at Line 46 to a repo-relative path (e.g., a path under the repository like "docs/..." or the appropriate relative path from this file) so both entries are portable across machines and follow the documented .worktrees convention.docs/session-restore/2026-03-13-launch-alpha/launch-tasks/9_clawREFORM_reddit-medium-quora-chain.md-10-10 (1)
10-10:⚠️ Potential issue | 🟠 MajorWorktree path conflicts with the launcher's
.worktrees/contract.
Line 10documents../clawreform-launch-..., but the live-window operator flow specifies.worktrees/...for sandbox-safe execution. This mismatch is likely to misroute task setup and operator expectations.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/launch-tasks/9_clawREFORM_reddit-medium-quora-chain.md` at line 10, The documented worktree path "../clawreform-launch-09-reddit-medium-quora-chain" in launch-tasks/9_clawREFORM_reddit-medium-quora-chain.md conflicts with the launcher's required sandbox-safe `.worktrees/` contract; update Line 10 to use the `.worktrees/` namespace (e.g., `.worktrees/clawreform-launch-09-reddit-medium-quora-chain`) so operator flows expect and create the task under the correct sandbox location, ensuring the documented path matches the runtime contract referenced by the launcher and live-window operator.docs/session-restore/2026-03-13-launch-alpha/launch-tasks/1_clawREFORM_pre-site-deployment.md-10-10 (1)
10-10:⚠️ Potential issue | 🟠 MajorFix path portability and launcher contract consistency.
Two doc path issues here:
Line 10:../clawreform-launch-01-pre-site-deploymentconflicts with the.worktrees/...convention used by the live-window launcher docs.Line 41:/home/ae/clawreform/...is machine-specific; use a repo-relative link so it renders and works for all contributors.Also applies to: 41-41
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/launch-tasks/1_clawREFORM_pre-site-deployment.md` at line 10, Replace the hardcoded and machine-specific paths to make docs portable and consistent with the launcher contract: change the Worktree reference `../clawreform-launch-01-pre-site-deployment` to the `.worktrees/...` convention used by the live-window launcher docs (e.g., `.worktrees/clawreform-launch-01-pre-site-deployment`) and replace any absolute machine path like `/home/ae/clawreform/...` with a repo-relative path (e.g., `clawreform/...` or `./clawreform/...`) so links render correctly for all contributors.scripts/cli-swarm/launch_live_windows.py-161-173 (1)
161-173:⚠️ Potential issue | 🟠 MajorRelaunches won't pick up updated task instructions.
copy_missing_tree()only fills gaps, the design baseline is only copied on first run, and the prompt file is never regenerated once it exists. Becausegit worktree addalready checks out tracked docs, edited launch docs in the main workspace are silently ignored even on a new worktree. Re-running the launcher after updating the task pack or baseline will keep launching stale instructions.♻️ Suggested refresh behavior
- if not target.exists(): - target.parent.mkdir(parents=True, exist_ok=True) - shutil.copy2(path, target) + target.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(path, target)- if not dst_design.exists(): - dst_design.parent.mkdir(parents=True, exist_ok=True) - shutil.copy2(src_design, dst_design) + dst_design.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src_design, dst_design)- if prompt_file.exists(): - return prompt_fileAlso applies to: 263-267, 329-353
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/cli-swarm/launch_live_windows.py` around lines 161 - 173, copy_missing_tree currently only copies missing files, causing updated baseline/task prompt files to be ignored; update copy_missing_tree to also overwrite destination files when the source is newer or content differs (e.g., compare mtime or checksum) and ensure directories are created as before, so tracked docs edited in the main workspace propagate into the worktree; apply the same refresh/overwrite logic to the other copy sites noted (around the blocks referenced at the other occurrences) so regenerated prompt/baseline files are replaced rather than left stale.scripts/cli-swarm/launch_live_windows.py-52-67 (1)
52-67:⚠️ Potential issue | 🟠 MajorThe launcher ignores the per-task CLI/model matrix.
Every
TaskSpechere is hardwired toopencodeandHUNTER_ALPHA_MODEL, but the launch commander/operator docs assign different CLIs and models per task. Running this launcher won't actually start the intended Claude/Gemini/pi/Codex workers, and tasks that rely onpi/Claude-specific behavior will start under the wrong client.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/cli-swarm/launch_live_windows.py` around lines 52 - 67, TASKS currently hardcodes the CLI and model to "opencode" and HUNTER_ALPHA_MODEL for every TaskSpec, causing wrong worker clients to be launched; update the TASKS construction so each TaskSpec uses the per-task CLI and model from the launch matrix (e.g., a TASK_CLI_MAP and TASK_MODEL_MAP or a single TASK_MATRIX dict) instead of the constants opencode and HUNTER_ALPHA_MODEL, or modify the TaskSpec instantiation to accept cli and model values passed in from the existing launcher configuration; ensure TaskSpec (class TaskSpec) fields and any code that consumes TASKS (the launcher/launch function) handle missing values by falling back to sensible defaults.docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot-308-309 (1)
308-309:⚠️ Potential issue | 🟠 MajorPreparation shouldn't fail just because
screenis missing.Line 309 resolves
screenduringsync_launch_inputs(), so even the prepare-only path exits early on hosts that only want the kitty session file. Check forscreenin the launch/open branches instead.Suggested fix
def make_screen_command(session_name: str, shell_command: str) -> list[str]: - return [require_binary("screen"), "-dmS", session_name, "bash", "-lc", shell_command] + return ["screen", "-dmS", session_name, "bash", "-lc", shell_command] ... if args.launch: + require_binary("screen") for item in selected: subprocess.run(shlex.split(item["screen_command"]), check=True) subprocess.run( [require_binary("kitty"), "--detach", "--session", str(session_file)], check=True, ) ... elif args.open_windows_only: + require_binary("screen") subprocess.run( [require_binary("kitty"), "--detach", "--session", str(session_file)], check=True, )Also applies to: 319-327, 403-415
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot` around lines 308 - 309, The prepare-only path fails because make_screen_command eagerly calls require_binary("screen") during sync_launch_inputs; change make_screen_command to not resolve the binary (return ["screen", "-dmS", session_name, "bash", "-lc", shell_command]) and move require_binary("screen") into the actual launch/open branches (the code around the current launch/open handling formerly at lines 319-327 and 403-415) so the binary is only checked when you actually attempt to start a screen session; alternatively, if you prefer explicitness, add a parameter to make_screen_command to accept the resolved screen path and call require_binary in the launch/open code before passing it in.scripts/cli-swarm/launch.py-312-313 (1)
312-313:⚠️ Potential issue | 🟠 MajorPrepare-only mode shouldn't require
screen.Line 313 resolves
screenwhile building everySessionSpec, solaunch.py --count 1fails on hosts withoutscreeneven when--launchis off.Suggested fix
- screen_command = [require_screen(), "-dmS", screen_name, *launch_command] + screen_command = ["screen", "-dmS", screen_name, *launch_command] ... if args.launch: + require_screen() for spec in specs: subprocess.run(spec.screen_command, check=True)Also applies to: 443-445
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/cli-swarm/launch.py` around lines 312 - 313, The code currently calls require_screen() while building screen_command (via variables screen_name and screen_command) for every SessionSpec, which forces resolving `screen` even in prepare-only runs; change this so require_screen() is only invoked when actually launching sessions (i.e., when --launch is true or the code path that executes the screen wrapper). Concretely, modify the logic that constructs screen_name/screen_command (and the analogous code around the blocks that reference screen_name at the 443-445 area) to skip wrapping launch_command in a screen call when prepare-only/--launch is False: keep launch_command as-is for prepare mode, or set screen_command to None/leave it unset, and call require_screen() and build the final screen_command only in the runtime/launcher function that executes the session. Ensure references to screen_name, screen_command, and require_screen() are adjusted accordingly.scripts/cli-swarm/launch.py-61-64 (1)
61-64:⚠️ Potential issue | 🟠 MajorHonor
--coordinatorconsistently or remove the flag.Line 298 hardcodes coordinator sessions to
pi, so--coordinator codexstill builds apicommand while the manifest records"coordinator": "codex". That makes the CLI misleading and can fail if only the requested coordinator is installed.Also applies to: 298-308, 418-423
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/cli-swarm/launch.py` around lines 61 - 64, The CLI flag "--coordinator" is declared but its value is ignored where coordinator sessions are constructed (you can see hardcoded "pi" in the coordinator-session construction around the block that builds the manifest and again in the later session creation code). Replace the hardcoded "pi" with the parsed coordinator value (e.g., use the argument/variable holding args.coordinator or the local "coordinator" variable) wherever coordinator sessions/commands are created so the runtime command matches the manifest; alternatively, if the design requires a single fixed coordinator, remove the "--coordinator" flag and all references to it to avoid divergence. Ensure you update all occurrences in the coordinator session construction blocks (the sections corresponding to the 298-308 and 418-423 ranges) to use the same coordinator symbol.docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot-75-75 (1)
75-75:⚠️ Potential issue | 🟠 MajorConstrain run names so they can't escape
.swarm/.Both Line 382 and Line 318 join the raw run name into a filesystem path. Absolute names or
..segments will write manifests, prompts, and logs outside the intended.swarm/<name>/directories.Suggested fix
+def resolve_run_root(base: pathlib.Path, name: str) -> pathlib.Path: + swarm_root = (base / ".swarm").resolve() + run_root = (swarm_root / name).resolve() + if run_root.parent != swarm_root: + raise SystemExit("--name must be a single directory name under .swarm/") + return run_root + ... - run_root = worktree / ".swarm" / run_name + run_root = resolve_run_root(worktree, run_name) ... - run_root = workspace / ".swarm" / args.name + run_root = resolve_run_root(workspace, args.name)Also applies to: 318-320, 382-383
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot` at line 75, The run name passed via the parser's "--name" argument is used directly when building paths (see uses at the join sites around lines referenced) and can escape the .swarm directory; add a validation/sanitization step: implement a small validator function (e.g., validate_run_name) and use it as the argparse type for parser.add_argument("--name", ...). The validator should reject absolute names (os.path.isabs), any path separators or ".." segments (check for os.sep or "/" or ".."), or alternatively enforce a safe regex like ^[A-Za-z0-9._-]+$; on failure raise argparse.ArgumentTypeError. Replace raw use of the parsed name at the path-joining sites with the validated value (or use pathlib.Path(name).name and ensure it equals the original to detect stripping) so manifests, prompts, and logs cannot be written outside .swarm/<name>/.docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot-142-146 (1)
142-146:⚠️ Potential issue | 🟠 MajorPut
-bbefore the worktree path.The current code produces
git worktree add <path> -b <branch> HEADwhen creating new branches, butgit worktree addexpects options like-bbefore<path>. This will cause branch creation to fail on first-time task branches.Suggested fix
- cmd = ["git", "worktree", "add", str(worktree_path)] + cmd = ["git", "worktree", "add"] if branch_exists(workspace, task.branch): - cmd.append(task.branch) + cmd.extend([str(worktree_path), task.branch]) else: - cmd.extend(["-b", task.branch, "HEAD"]) + cmd.extend(["-b", task.branch, str(worktree_path), "HEAD"])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot` around lines 142 - 146, The current construction of cmd puts the worktree path before the -b option for new branches which makes git fail; update the branch-not-exists branch of the conditional so options come before the path (use cmd = ["git","worktree","add","-b", task.branch, str(worktree_path), "HEAD"] or insert "-b" and task.branch into cmd before str(worktree_path]) while leaving the existing-branch case (cmd.append(task.branch)) unchanged; reference symbols: cmd, branch_exists(workspace, task.branch), worktree_path, task.branch.crates/clawreform-api/src/routes.rs-9090-9096 (1)
9090-9096:⚠️ Potential issue | 🟠 MajorChanging
COMPANY_AGENT_IDwill hide previously saved company data.This ID is the storage namespace for
company_goalsandcompany_issues. Switching it means existing deployments start reading an empty namespace, so saved goals/issues effectively disappear until you migrate or dual-read the previous ID.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-api/src/routes.rs` around lines 9090 - 9096, Do not change the storage namespace represented by COMPANY_AGENT_ID because it maps persisted data for company_goals and company_issues; instead restore the original constant value (leave COMPANY_AGENT_ID untouched) or, if a change is unavoidable, implement a migration/dual-read strategy: add code to read from the old AgentId as well as the new one and migrate records for company_goals and company_issues (or provide a one-time migration utility), update documentation/comments near COMPANY_AGENT_ID to warn about the persistence impact, and ensure any deploy includes the migration path before switching live reads to the new ID.crates/clawreform-api/src/server.rs-305-317 (1)
305-317: 🛠️ Refactor suggestion | 🟠 MajorRoute these new handlers through
routes.rs.These additions wire
crate::auto_import::*andcrate::openclaw::*straight into the router, which bypasses the API surface split this repo expects. If the logic should stay in dedicated modules, add thin forwarding handlers inroutes.rsand register those here instead.As per coding guidelines, "New API routes must be registered in
server.rsrouter AND implemented inroutes.rs".Also applies to: 648-703
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-api/src/server.rs` around lines 305 - 317, The new routes currently register crate::auto_import::scan_directory, import_items, and get_suggestions (and similarly the crate::openclaw handlers referenced later) directly in server.rs; instead add thin forwarding handlers in routes.rs (e.g., auto_import_scan, auto_import_import_items, auto_import_get_suggestions) that call the existing crate::auto_import functions, export them from routes.rs, and then register those forwarding handlers in server.rs where you currently call crate::auto_import::scan_directory, crate::auto_import::import_items, and crate::auto_import::get_suggestions; do the same for the openclaw handlers mentioned in the later block so all new API endpoints are implemented in routes.rs and only routed from server.rs.crates/clawreform-api/static/js/pages/import.js-96-103 (1)
96-103:⚠️ Potential issue | 🟠 MajorMake
selectAll()idempotent.Right now it toggles every eligible row. If the user manually selected one item first, clicking "Select all" will deselect that item instead of leaving it selected.
🛠️ Suggested fix
selectAll() { - var self = this; - for (var item of this.discoveredItems) { - if (item.can_import && !item.already_installed) { - self.toggleSelect(item); - } - } + this.selectedItems = this.discoveredItems.filter(function(item) { + return item.can_import && !item.already_installed; + }); },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-api/static/js/pages/import.js` around lines 96 - 103, selectAll currently toggles every eligible item which makes it non-idempotent; update selectAll (in this file) to only call toggleSelect for items that are eligible (item.can_import && !item.already_installed) AND not already selected by checking the item's selection state (e.g., item.selected or item.isSelected()). In short: replace the unconditional toggleSelect call inside the loop with a conditional that calls toggleSelect only when the item is not already selected so clicking "Select all" never deselects user-selected rows.crates/clawreform-api/static/js/pages/import.js-51-77 (1)
51-77:⚠️ Potential issue | 🟠 MajorClear stale scan state and always reset
scanning.The early
returnand thecatchboth leavethis.scanningstucktrue, and a failed rescan keeps the previous results/selection around. The seconddiscoveredItemsassignment also drops the|| []guards, so a partial response can throw before cleanup.🛠️ Suggested fix
async scanDirectory(dir) { this.scanPath = dir; this.scanning = true; this.scanError = ''; + this.scanResults = null; + this.discoveredItems = []; + this.selectedItems = []; try { var data = await ClawReformAPI.post('/api/import/scan', { directory: dir }); if (data.error) { this.scanError = data.error; return; } this.scanResults = data; this.discoveredItems = [] .concat(data.mcp_servers || []) .concat(data.skills || []) .concat(data.plugins || []); - - // Flatten for UI display - this.discoveredItems = this.scanResults.mcp_servers - .concat(this.scanResults.skills) - .concat(this.scanResults.plugins); - this.scanning = false; } catch(e) { this.scanError = 'Scan failed: ' + e.message; this.showToast('error', 'Scan failed: ' + e.message); + } finally { + this.scanning = false; } },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-api/static/js/pages/import.js` around lines 51 - 77, The scanDirectory function leaves this.scanning true and stale results on early-return or error; update scanDirectory (the async method that calls ClawReformAPI.post) to always set this.scanning = false in a finally block, clear/initialize this.scanResults / this.discoveredItems / this.scanError before returning when data.error is present, and when building discoveredItems use the guarded concatenation (e.g., (data.mcp_servers || []) .concat(data.skills || []) .concat(data.plugins || [])) instead of the duplicate unguarded assignment so partial responses won't throw.crates/clawreform-runtime/src/trace_context.rs-14-18 (1)
14-18:⚠️ Potential issue | 🟠 MajorThis trace context can be lost silently.
tokio::task_local!is per-task, so it will not automatically follow spawned work, yet the module docs read like propagation is end-to-end. On top of that,set_trace_id()/clear_trace_id()ignoretry_withfailures, so missing scope just drops the trace with no signal. Please either pass/re-scopeTraceIdexplicitly for spawned work, or narrow the contract and make missing context fail loudly.Also applies to: 33-45
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-runtime/src/trace_context.rs` around lines 14 - 18, The task-local TRACE_CONTEXT (tokio::task_local!) is currently silently dropped for spawned tasks because set_trace_id()/clear_trace_id() ignore try_with failures; update the implementation to either explicitly propagate the TraceId when spawning work or make missing context fail loudly: replace the silent try_with ignores in set_trace_id()/clear_trace_id()/any try_with sites so they return Result or log/panic on Err, and add a helper (e.g., spawn_with_trace or scope_trace) that takes a TraceId and re-scopes TRACE_CONTEXT for spawned tokio::spawn tasks; ensure the unique symbols TRACE_CONTEXT, set_trace_id, clear_trace_id, try_with (and any spawn helper you add) are updated so trace propagation is explicit or failures are surfaced.crates/clawreform-api/static/js/app.js-518-520 (1)
518-520:⚠️ Potential issue | 🟠 MajorDon't auto-create a seed agent when an existing agent just lacks markdown.
The widened
obsidianCanSeedAgentcheck means simply opening#obsidiancan now create a brand newmemory-seedagent for an otherwise normal workspace. That is a hidden write side effect on a navigation path, and it also flips future graph loads over to the synthetic agent via the stored preferred id. Limit silent seeding to the zero-agent case, or make the no-markdown path an explicit CTA.Safer immediate guard
- if (this.obsidianCanSeedAgent) { + if (/No agents found/i.test(this.obsidianGraphError || '')) { await this.createObsidianSeedAgent({ silent: true }); }Also applies to: 545-555
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-api/static/js/app.js` around lines 518 - 520, The obsidianCanSeedAgent getter currently treats "no markdown files" as permission to auto-create a seed agent, causing unintended silent writes; change its logic to only allow automatic seeding when there are zero existing agents (e.g., check this.agents?.length === 0) or otherwise require an explicit user action/CTA for the no-markdown path. Update the obsidianCanSeedAgent getter and any other occurrence of the same widened check (the similar block around lines 545-555) to include the zero-agent guard (or replace silent seeding with an explicit CTA flow) so opening `#obsidian` doesn't create a memory-seed for a workspace that already has agents.openclaw/docker-compose.openclaw.yml-17-25 (1)
17-25:⚠️ Potential issue | 🟠 MajorDon't expose the datastores with repo-tracked credentials.
Docker publishes these ports on all host interfaces by default. With
POSTGRES_PASSWORD: openclaw_secretand an unauthenticated Redis on6379, anyone who can reach the developer host can attach to the stack. Bind the datastore ports to127.0.0.1/exposeonly, and source the passwords from an untracked.envinstead of hardcoding them into the compose file and everyDATABASE_URL.Also applies to: 37-41, 62-63, 91-92, 115-116, 145-146, 170-172
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openclaw/docker-compose.openclaw.yml` around lines 17 - 25, The compose file currently hardcodes credentials and publishes DB ports to all interfaces; change the postgres service to bind the port to localhost (e.g., "127.0.0.1:5432:5432" or use expose: - "5432") and replace POSTGRES_PASSWORD: openclaw_secret with a variable reference (POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}") sourced from an untracked .env file; apply the same pattern for other datastore services (e.g., Redis on 6379 and any other POSTGRES* or DATABASE_URL entries mentioned) so credentials are removed from the repo and ports are not published publicly, and update any DATABASE_URL usages to read from the .env values (e.g., DATABASE_URL: "${DATABASE_URL}").crates/clawreform-api/src/openclaw.rs-110-113 (1)
110-113:⚠️ Potential issue | 🟠 MajorManual JSON string formatting can produce invalid JSON if error contains quotes.
If the error message contains double quotes, backslashes, or other special characters, the resulting JSON will be malformed. Use
serde_json::json!for safe JSON construction.🐛 Proposed fix (apply to all similar occurrences)
- Err(e) => (StatusCode::BAD_GATEWAY, format!("{{\"error\": \"{}\"}}", e)), + Err(e) => (StatusCode::BAD_GATEWAY, serde_json::json!({"error": e.to_string()}).to_string()),This pattern appears throughout the file (Lines 110, 113, 129, 132, 148, 151, 171, 174, 187, 190, 207, 210, 226, 229, 245, 248, 267, 270, 291, 294, 310, 313, 329, 332, 345, 348). Consider extracting a helper function:
fn error_response(e: impl std::fmt::Display) -> (StatusCode, String) { (StatusCode::BAD_GATEWAY, serde_json::json!({"error": e.to_string()}).to_string()) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/clawreform-api/src/openclaw.rs` around lines 110 - 113, Replace manual JSON string construction like format!("{{\"error\": \"{}\"}}", e) with a safe helper function error_response that returns (StatusCode::BAD_GATEWAY, String) and uses serde_json::json! to build {"error": e.to_string()} and .to_string(); call error_response(e) at each occurrence (e.g., the two instances shown and the other listed lines) so error messages with quotes or escapes produce valid JSON.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2088b161-1999-4386-8841-992bb98c5c4a
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (94)
.gitignorecrates/clawreform-api/Cargo.tomlcrates/clawreform-api/src/auto_import.rscrates/clawreform-api/src/lib.rscrates/clawreform-api/src/middleware.rscrates/clawreform-api/src/openclaw.rscrates/clawreform-api/src/routes.rscrates/clawreform-api/src/server.rscrates/clawreform-api/src/webchat.rscrates/clawreform-api/static/css/components.csscrates/clawreform-api/static/index_body.htmlcrates/clawreform-api/static/js/app.jscrates/clawreform-api/static/js/pages/import.jscrates/clawreform-api/static/js/pages/model-selector.jscrates/clawreform-api/static/js/pages/settings.jscrates/clawreform-api/static/js/pages/skills.jscrates/clawreform-api/tests/api_integration_test.rscrates/clawreform-api/tests/daemon_lifecycle_test.rscrates/clawreform-api/tests/load_test.rscrates/clawreform-cli/src/tui/mod.rscrates/clawreform-kernel/src/kernel.rscrates/clawreform-kernel/src/registry.rscrates/clawreform-memory/src/session.rscrates/clawreform-memory/src/structured.rscrates/clawreform-runtime/src/agent_loop.rscrates/clawreform-runtime/src/compactor.rscrates/clawreform-runtime/src/lib.rscrates/clawreform-runtime/src/trace_context.rscrates/clawreform-types/src/agent.rscrates/clawreform-types/src/company.rscrates/clawreform-types/src/lib.rscrates/clawreform-types/src/openclaw.rscrates/clawreform-wire/src/peer.rsdocs/cli-swarm.mddocs/design/launch-metallic-baseline.mddocs/launch-tasks/0_clawREFORM_launch-commander.mddocs/launch-tasks/10_clawREFORM_content-creator.mddocs/launch-tasks/11_clawREFORM_content-distributor.mddocs/launch-tasks/12_clawREFORM_email-list-super-sherlock.mddocs/launch-tasks/13_clawREFORM_launch-control-room.mddocs/launch-tasks/14_clawREFORM_design-system-translation.mddocs/launch-tasks/15_clawREFORM_live-window-operator-sheet.mddocs/launch-tasks/1_clawREFORM_pre-site-deployment.mddocs/launch-tasks/2_clawREFORM_audit_dl-path.mddocs/launch-tasks/3_clawREFORM_release-packaging-proof.mddocs/launch-tasks/4_clawREFORM_onboarding-first-run-smoke.mddocs/launch-tasks/5_clawREFORM_parallel-proof-screenshots.mddocs/launch-tasks/6_clawREFORM_public-alpha-go-live.mddocs/launch-tasks/7_clawREFORM_twitter-x-launch-chain.mddocs/launch-tasks/8_clawREFORM_youtube-launch-automation.mddocs/launch-tasks/9_clawREFORM_reddit-medium-quora-chain.mddocs/session-restore/2026-03-13-launch-alpha/README.mddocs/session-restore/2026-03-13-launch-alpha/constraints-summary.mddocs/session-restore/2026-03-13-launch-alpha/conversation.mddocs/session-restore/2026-03-13-launch-alpha/design/launch-metallic-baseline.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/0_clawREFORM_launch-commander.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/10_clawREFORM_content-creator.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/11_clawREFORM_content-distributor.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/12_clawREFORM_email-list-super-sherlock.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/13_clawREFORM_launch-control-room.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/14_clawREFORM_design-system-translation.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/15_clawREFORM_live-window-operator-sheet.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/1_clawREFORM_pre-site-deployment.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/2_clawREFORM_audit_dl-path.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/3_clawREFORM_release-packaging-proof.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/4_clawREFORM_onboarding-first-run-smoke.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/5_clawREFORM_parallel-proof-screenshots.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/6_clawREFORM_public-alpha-go-live.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/7_clawREFORM_twitter-x-launch-chain.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/8_clawREFORM_youtube-launch-automation.mddocs/session-restore/2026-03-13-launch-alpha/launch-tasks/9_clawREFORM_reddit-medium-quora-chain.mddocs/session-restore/2026-03-13-launch-alpha/non-sandbox-delta.mddocs/session-restore/2026-03-13-launch-alpha/prompts/01-pre-site-deployment.mddocs/session-restore/2026-03-13-launch-alpha/prompts/02-audit-dl-path.mddocs/session-restore/2026-03-13-launch-alpha/prompts/04-onboarding-first-run-smoke.mddocs/session-restore/2026-03-13-launch-alpha/prompts/05-parallel-proof-screenshots.mddocs/session-restore/2026-03-13-launch-alpha/prompts/10-content-creator.mddocs/session-restore/2026-03-13-launch-alpha/prompts/13-launch-control-room.mddocs/session-restore/2026-03-13-launch-alpha/prompts/14-design-system-translation.mddocs/session-restore/2026-03-13-launch-alpha/restore-checklist.mddocs/session-restore/2026-03-13-launch-alpha/state/kitty-live.sessiondocs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshotdocs/session-restore/2026-03-13-launch-alpha/state/visible-launch-manifest.jsondocs/session-restore/2026-03-13-launch-alpha/working-state.mdopenclaw/IMPLEMENTATION_PACK.mdopenclaw/docker-compose.openclaw.ymlopenclaw/openclaw_registry.sqlscripts/cli-swarm/launch.pyscripts/cli-swarm/launch_live_windows.pyscripts/cli-swarm/proof-demo.shscripts/cli-swarm/status.pyscripts/cli-swarm/verify.shscripts/dashboard-proof.shsite/index.html
| include_str!("../static/js/pages/model-selector.js"), | ||
| "\n", | ||
| include_str!("../static/js/pages/import.js"), | ||
| "\n", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify HTML elements exist for the new page scripts
# Check for model-selector related elements
echo "=== Checking for model-selector HTML elements ==="
rg -n "model-selector|modelSelector" crates/clawreform-api/static/index_body.html
# Check for import page related elements
echo "=== Checking for import page HTML elements ==="
rg -n "import.*page|importPage" crates/clawreform-api/static/index_body.html
# Verify the JS files exist
echo "=== Verifying JS files exist ==="
ls -la crates/clawreform-api/static/js/pages/model-selector.js crates/clawreform-api/static/js/pages/import.js 2>&1Repository: aegntic/clawreform
Length of output: 466
Add HTML element for model-selector page or remove the script inclusion.
The import.js script has a corresponding HTML element (<div x-show="tab === 'import'" x-data="importPage()"> at line 5016 of index_body.html). However, model-selector.js is included in webchat.rs but has no corresponding HTML element in index_body.html. Per the pattern established by the import page, dashboard page scripts require both the script inclusion and a matching HTML div element with Alpine.js data binding.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/clawreform-api/src/webchat.rs` around lines 197 - 200, The pull
request currently includes model-selector.js in webchat.rs without a matching
Alpine/HTML container in index_body.html; either remove the
include_str!("../static/js/pages/model-selector.js") from the list in webchat.rs
or add a corresponding HTML element in index_body.html similar to the import
page (e.g., a <div x-show="tab === 'model-selector'"
x-data="modelSelectorPage()">) so the script has a matching Alpine binding;
update the symbol names model-selector.js and modelSelectorPage (or whichever
Alpine initializer is defined) to ensure the script and HTML div names match.
| showApiKeyFix() { | ||
| // Reset the API key configuration and show the OpenRouter gate | ||
| this.openRouterKeyInput = ''; | ||
| this.openRouterError = ''; | ||
| this.openRouterProviderStatus = 'unknown'; | ||
| this.showOpenRouterGate = true; | ||
| // Navigate to wizard if not already there | ||
| if (Alpine.store('app').page !== 'wizard') { | ||
| this.navigate('wizard'); | ||
| } |
There was a problem hiding this comment.
showApiKeyFix() is navigating through the wrong object.
page and navigate() belong to the app() component, not the global store. This code therefore always enters the branch and then throws TypeError: this.navigate is not a function, so the recovery button cannot reach the wizard.
🐛 Minimal fix
showApiKeyFix() {
// Reset the API key configuration and show the OpenRouter gate
this.openRouterKeyInput = '';
this.openRouterError = '';
this.openRouterProviderStatus = 'unknown';
this.showOpenRouterGate = true;
- // Navigate to wizard if not already there
- if (Alpine.store('app').page !== 'wizard') {
- this.navigate('wizard');
- }
+ if ((window.location.hash || '').replace('#', '') !== 'wizard') {
+ window.location.hash = 'wizard';
+ }
},🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/clawreform-api/static/js/app.js` around lines 256 - 265, In
showApiKeyFix(), the code checks and calls navigation on Alpine.store('app')
which doesn't expose page/navigate; replace the store access with the component
instance so the correct methods are used: change the condition and call from if
(Alpine.store('app').page !== 'wizard') { this.navigate('wizard'); } to use this
(e.g., if (this.page !== 'wizard') { this.navigate('wizard'); }) within the
showApiKeyFix method so it reads the component's page and invokes its navigate()
method.
| var commonDirs = [ | ||
| '~/.claude/skills', | ||
| '~/.codex/skills', | ||
| '~/.gemini/skills', | ||
| '~/.opencode/skills', | ||
| '~/.cline/skills', | ||
| '~/.aider/skills', | ||
| '~/.cursor/skills', | ||
| '~/.continue/skills', | ||
| '~/.local/share/mcp/skills', |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="$(fd -a '^auto_import\.rs$' crates/clawreform-api/src | head -n1)"
echo "File: $file"
rg -n -C4 'home_dir|dirs::home_dir|shellexpand|tilde|expanduser|canonicalize|scan.*directory|directory:' "$file" || trueRepository: aegntic/clawreform
Length of output: 2034
🏁 Script executed:
file="crates/clawreform-api/static/js/pages/skills.js"
if [ -f "$file" ]; then
sed -n '359,363p' "$file"
fiRepository: aegntic/clawreform
Length of output: 323
Fix tilde expansion for fallback scan paths on the backend.
The frontend sends ~/.claude/skills literally to /api/import/scan (lines 359–363), but the backend treats it as a literal path without expanding ~ to the user's home directory. The line let dir = PathBuf::from(&body.directory); in crates/clawreform-api/src/auto_import.rs:99 must expand the tilde before filesystem operations, otherwise fallback directory scans will silently fail.
Use a crate like shellexpand or manually expand ~ using dirs::home_dir() before creating the PathBuf.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/clawreform-api/static/js/pages/skills.js` around lines 312 - 321, The
backend is treating incoming directories like "~/.claude/skills" as literal
paths; locate where PathBuf::from(&body.directory) is used (in the import/scan
handler in auto_import.rs) and expand a leading tilde before creating the
PathBuf (use shellexpand::tilde or expand manually with dirs::home_dir()), then
continue with the existing filesystem operations using the expanded path; ensure
you only expand a leading "~" or "~/" and preserve other inputs.
| def repo_root() -> pathlib.Path: | ||
| return pathlib.Path(__file__).resolve().parents[2] |
There was a problem hiding this comment.
repo_root() resolves to the wrong directory.
For this file path, parents[2] is <repo>/docs/session-restore, not the repository root. All later path joins then look for docs/launch-tasks under the wrong tree and write .swarm/ in the wrong place.
Suggested fix
def repo_root() -> pathlib.Path:
- return pathlib.Path(__file__).resolve().parents[2]
+ current = pathlib.Path(__file__).resolve()
+ for parent in current.parents:
+ if (parent / ".git").exists():
+ return parent
+ raise SystemExit("Could not locate the repository root")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot`
around lines 104 - 105, The repo_root() helper incorrectly uses
pathlib.Path(__file__).resolve().parents[2] (which yields
<repo>/docs/session-restore); update repo_root() to return the actual repository
root by using the correct parent index
pathlib.Path(__file__).resolve().parents[4] (or replace with a small loop that
walks up until it finds a repo marker like .git/pyproject.toml) so all
downstream joins (in code that uses repo_root()) point at the real repository
root.
| def local_env_exports(run_root: pathlib.Path, cli_name: str, session_dir: pathlib.Path) -> dict[str, str]: | ||
| home_dir = run_root / "homes" / cli_name | ||
| for directory in ( | ||
| home_dir, | ||
| home_dir / ".config", | ||
| home_dir / ".local" / "share", | ||
| home_dir / ".local" / "state", | ||
| home_dir / ".cache", | ||
| home_dir / ".pi" / "agent", | ||
| home_dir / ".codex", | ||
| home_dir / ".config" / "opencode", | ||
| home_dir / ".local" / "share" / "opencode", | ||
| home_dir / ".gemini", | ||
| home_dir / ".claude", | ||
| session_dir, | ||
| ): | ||
| directory.mkdir(parents=True, exist_ok=True) | ||
|
|
||
| env = { | ||
| "HOME": str(home_dir), | ||
| "XDG_CONFIG_HOME": str(home_dir / ".config"), | ||
| "XDG_DATA_HOME": str(home_dir / ".local" / "share"), | ||
| "XDG_STATE_HOME": str(home_dir / ".local" / "state"), | ||
| "XDG_CACHE_HOME": str(home_dir / ".cache"), | ||
| "PI_CODING_AGENT_DIR": str(home_dir / ".pi" / "agent"), | ||
| "PI_OFFLINE": "1", | ||
| "CODEX_HOME": str(home_dir / ".codex"), | ||
| "OPENCODE_CONFIG_HOME": str(home_dir / ".config" / "opencode"), | ||
| "OPENCODE_DATA_HOME": str(home_dir / ".local" / "share" / "opencode"), | ||
| "GEMINI_CLI_HOME": str(home_dir / ".gemini"), | ||
| "CLAUDE_CONFIG_DIR": str(home_dir / ".claude"), | ||
| "SWARM_SESSION_DIR": str(session_dir), | ||
| } | ||
| forwarded = [ | ||
| "OPENAI_API_KEY", | ||
| "ANTHROPIC_API_KEY", | ||
| "GEMINI_API_KEY", | ||
| "GOOGLE_API_KEY", | ||
| "OPENROUTER_API_KEY", | ||
| "OPENCODE_API_KEY", | ||
| ] | ||
| for key in forwarded: | ||
| if key in os.environ: | ||
| env[key] = os.environ[key] | ||
| return env |
There was a problem hiding this comment.
Don't write API keys into visible-launch-manifest.json.
The forwarded provider keys are embedded into shell_command, copied into each task's screen_command, and then persisted in the manifest. That writes live secrets under .swarm/ on disk.
Also applies to: 298-305, 329-340, 364-371
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@docs/session-restore/2026-03-13-launch-alpha/state/launch_live_windows.py.snapshot`
around lines 162 - 206, The code in local_env_exports collects sensitive API
keys into the env dict (forwarded list) which then get embedded into
shell_command/screen_command and persisted to visible-launch-manifest.json;
remove or redact these secrets before any manifest serialization and instead
supply them only at runtime. Modify local_env_exports (and any code that builds
shell_command/screen_command) to: 1) stop placing forwarded keys into any data
structure that is later serialized to disk (omit them from the returned env dict
used for manifest), 2) provide a runtime-only mechanism to inject these keys
when launching processes (e.g., pass them via the process environment directly
or a non-persisted runtime config), and 3) ensure manifest-writing code filters
out or masks keys named in forwarded (OPENAI_API_KEY, ANTHROPIC_API_KEY,
GEMINI_API_KEY, GOOGLE_API_KEY, OPENROUTER_API_KEY, OPENCODE_API_KEY) so they
never appear in visible-launch-manifest.json; apply the same change to the other
similar blocks referenced (lines ~298-305, 329-340, 364-371).
| CREATE INDEX idx_artifacts_owner ON artifacts(owner_agent); | ||
| CREATE INDEX idx_artifacts_project ON artifacts(project); | ||
| CREATE INDEX idx_artifacts_type ON artifacts(artifact_type); | ||
| CREATE INDEX idx_artifacts_created ON artifacts(created_at DESCENDING); |
There was a problem hiding this comment.
Same syntax error: DESCENDING → DESC.
🐛 Proposed fix
-CREATE INDEX idx_artifacts_created ON artifacts(created_at DESCENDING);
+CREATE INDEX idx_artifacts_created ON artifacts(created_at DESC);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| CREATE INDEX idx_artifacts_created ON artifacts(created_at DESCENDING); | |
| CREATE INDEX idx_artifacts_created ON artifacts(created_at DESC); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openclaw/openclaw_registry.sql` at line 227, The CREATE INDEX statement for
idx_artifacts_created uses invalid SQL syntax "DESCENDING"; update the index
creation for artifacts on created_at to use the correct direction token "DESC"
(i.e., modify the idx_artifacts_created definition to use created_at DESC).
| CREATE INDEX idx_dispatch_trace ON dispatch_records(trace_id); | ||
| CREATE INDEX idx_dispatch_task ON dispatch_records(task_id); | ||
| CREATE INDEX idx_dispatch_agent ON dispatch_records(selected_agent); | ||
| CREATE INDEX idx_dispatch_created ON dispatch_records(created_at DESCENDING); |
There was a problem hiding this comment.
Same syntax error: DESCENDING → DESC.
🐛 Proposed fix
-CREATE INDEX idx_dispatch_created ON dispatch_records(created_at DESCENDING);
+CREATE INDEX idx_dispatch_created ON dispatch_records(created_at DESC);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| CREATE INDEX idx_dispatch_created ON dispatch_records(created_at DESCENDING); | |
| CREATE INDEX idx_dispatch_created ON dispatch_records(created_at DESC); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@openclaw/openclaw_registry.sql` at line 233, The CREATE INDEX statement for
idx_dispatch_created on dispatch_records uses the invalid keyword DESCENDING;
update the index definition in the CREATE INDEX statement (the
idx_dispatch_created index on dispatch_records) to use the correct SQL sort
keyword DESC instead of DESCENDING so the statement becomes valid.
| forwarded = [ | ||
| "OPENAI_API_KEY", | ||
| "ANTHROPIC_API_KEY", | ||
| "GEMINI_API_KEY", | ||
| "GOOGLE_API_KEY", | ||
| "OPENROUTER_API_KEY", | ||
| "OPENCODE_API_KEY", | ||
| ] | ||
| for key in forwarded: | ||
| if key in os.environ: | ||
| env[key] = os.environ[key] | ||
| return env |
There was a problem hiding this comment.
Don't persist forwarded API keys into generated artifacts.
The env dict includes live credentials, render_agent_shell_command() serializes them into a shell string, and that string is then written into the starter scripts and visible-launch-manifest.json. That leaves plaintext secrets under .swarm/ and every prepared worktree. Pass secrets through the tmux/subprocess environment instead, and only record non-sensitive metadata in generated files.
Also applies to: 423-426, 451-485, 580-595
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/cli-swarm/launch_live_windows.py` around lines 315 - 326, The current
code appends live API keys from os.environ into the env dict (the forwarded list
and the env return used by render_agent_shell_command()), which then gets
serialized into starter scripts and visible-launch-manifest.json; remove adding
secrets into the returned env and stop serializing them. Instead, keep only
non-sensitive metadata in env/manifest, and when launching agents (where
render_agent_shell_command(), tmux/subprocess launch code, or any start_agent_*
functions are invoked) inject secrets into the child environment at runtime by
reading os.environ inside the launch path or passing a separate secure_env to
subprocess.Popen/tmux environment APIs; specifically, stop populating the
forwarded keys into env (the forwarded list and the loop that sets env[key] =
os.environ[key]) and ensure render_agent_shell_command() and any code that
writes starter scripts only use the sanitized metadata, while the actual
process-launch code reads secrets directly from os.environ and supplies them to
the process environment without persisting them to disk.
| def ensure_clean_dir(path: pathlib.Path, force: bool) -> None: | ||
| if path.exists(): | ||
| if not force: | ||
| raise SystemExit(f"{path} already exists; rerun with --force to replace it.") | ||
| shutil.rmtree(path) | ||
| path.mkdir(parents=True, exist_ok=True) |
There was a problem hiding this comment.
Constrain --name to a direct child of .swarm/.
Line 397 trusts args.name as a path fragment. --name .. --force resolves outside .swarm/, so ensure_clean_dir() can recursively delete the repo root or any other reachable directory.
Suggested fix
+def resolve_run_root(workspace: pathlib.Path, name: str) -> pathlib.Path:
+ swarm_root = (workspace / ".swarm").resolve()
+ run_root = (swarm_root / name).resolve()
+ if run_root.parent != swarm_root:
+ raise SystemExit("--name must be a single directory name under .swarm/")
+ return run_root
+
...
- run_root = workspace / ".swarm" / args.name
+ run_root = resolve_run_root(workspace, args.name)Also applies to: 396-398
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/cli-swarm/launch.py` around lines 150 - 155, The code currently
trusts args.name as a path fragment which allows escapes like ".." and enables
deleting outside .swarm; validate args.name before using it: ensure it's not
absolute, contains no path separators (e.g. Path(args.name).name == args.name),
and is not "." or "..", then construct the target as swarm_dir / args.name and
pass that safe path to ensure_clean_dir; update the code paths where args.name
is used (e.g., where you build the .swarm child and where ensure_clean_dir(path,
force) is called) to perform this validation first and raise a clear error if
the name is invalid.
| def local_env_exports(root: pathlib.Path, tool: str, session_dir: pathlib.Path) -> dict[str, str]: | ||
| home_dir = root / "homes" / tool | ||
| for directory in ( | ||
| home_dir, | ||
| home_dir / ".config", | ||
| home_dir / ".local" / "share", | ||
| home_dir / ".local" / "state", | ||
| home_dir / ".cache", | ||
| home_dir / ".pi" / "agent", | ||
| home_dir / ".codex", | ||
| home_dir / ".config" / "opencode", | ||
| home_dir / ".local" / "share" / "opencode", | ||
| home_dir / ".gemini", | ||
| home_dir / ".claude", | ||
| session_dir, | ||
| ): | ||
| directory.mkdir(parents=True, exist_ok=True) | ||
| env = { | ||
| "HOME": str(home_dir), | ||
| "XDG_CONFIG_HOME": str(home_dir / ".config"), | ||
| "XDG_DATA_HOME": str(home_dir / ".local" / "share"), | ||
| "XDG_STATE_HOME": str(home_dir / ".local" / "state"), | ||
| "XDG_CACHE_HOME": str(home_dir / ".cache"), | ||
| "PI_CODING_AGENT_DIR": str(home_dir / ".pi" / "agent"), | ||
| "PI_OFFLINE": "1", | ||
| "CODEX_HOME": str(home_dir / ".codex"), | ||
| "OPENCODE_CONFIG_HOME": str(home_dir / ".config" / "opencode"), | ||
| "OPENCODE_DATA_HOME": str(home_dir / ".local" / "share" / "opencode"), | ||
| "GEMINI_CLI_HOME": str(home_dir / ".gemini"), | ||
| "CLAUDE_CONFIG_DIR": str(home_dir / ".claude"), | ||
| "SWARM_SESSION_DIR": str(session_dir), | ||
| } | ||
| for key in ("OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY", "OPENCODE_API_KEY", "OPENROUTER_API_KEY"): | ||
| if key in os.environ: | ||
| env[key] = os.environ[key] | ||
| return env |
There was a problem hiding this comment.
Don't persist token-bearing launch commands.
local_env_exports() forwards live API keys, render_shell_command() bakes them into the shell string, and Lines 415-440 write/print that string via launch_command and screen_command. That leaks secrets to .swarm/<name>/manifest.json and stdout.
Also applies to: 203-206, 314-325, 415-440
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/cli-swarm/launch.py` around lines 165 - 200, local_env_exports
currently includes live API keys and
render_shell_command/launch_command/screen_command bake them into persisted
shell strings (which are written to manifest.json and stdout), leaking secrets;
to fix, stop embedding secret values: remove API token keys (OPENAI_API_KEY,
ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENCODE_API_KEY, OPENROUTER_API_KEY) from
any data that will be persisted or printed, and instead pass them only at
runtime via process environment or a temp env-file with restrictive permissions.
Concretely, change local_env_exports to exclude token values when the output
will be stored/printed, update
render_shell_command/launch_command/screen_command to reference tokens by name
(e.g., rely on the invoking process env or an env file path) rather than
interpolating their values into the command string, and ensure any manifest.json
or stdout writers redact or omit these keys before writing.
Summary
Test plan
site/index.htmlin browser🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation