Skip to content

Feat/agent eval showcase#106

Merged
cnjack merged 4 commits into
mainfrom
feat/agent-eval-showcase
Jul 3, 2026
Merged

Feat/agent eval showcase#106
cnjack merged 4 commits into
mainfrom
feat/agent-eval-showcase

Conversation

@cnjack

@cnjack cnjack commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added a polished documentation site and homepage with updated navigation, searchable docs, and a new showcase area.
    • Introduced several interactive demo pages, including analytics, landing hero, pricing, to-do, particle, and SVG chart examples.
    • Added evaluation report pages and summaries for run results and defects.
  • Documentation

    • Expanded product documentation covering setup, configuration, tools, sessions, models, SSH, MCP, subagents, and more.

cnjack and others added 4 commits July 2, 2026 10:08
Add the complete jcode Agent autonomous-execution evaluation suite:
- Round-table discussion artifact (roundtable/)
- ACP headless harness (harness/) with isolated-HOME orchestration (suite/)
- 65-run prior evaluation report (report/report.html, analysis/)
- 6 new frontend test cases and deterministic oracles (suite/testcases.json, verify.py)
- 18-run frontend batch results: 17/18 passed (94%), clean end_turns
- Self-contained showcase landing page (showcase/index.html) displaying the
  prior report metrics, the 6 discovered defects, and the 6 generated frontend
  projects as live iframes with per-project model/runtime/token metadata.

All generated frontend projects render offline with no external CDN assets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
…frames

Redesign the agent-eval landing experience after open-design.ai:
- Add agent-eval/site/ with shared CSS/JS, nav, and six pages: index,
  showcase, report, findings, roundtable, docs.
- Apply warm cream background (#f6f3ec), serif display type, pill buttons,
  white cards, numbered sections, and generous whitespace.
- Convert existing docs (README, report, findings, roundtable) into the
  new site pages while preserving the original report in an iframe.
- Embed the 6 generated frontend projects in the showcase as full-width
  780px-tall iframes (responsive down to 460px on mobile) so they are
  actually usable, not thumbnails.
- Mirror generated project files under site/projects/ for self-contained
  browsing, and redirect the old showcase/index.html to the new site.
- Update README to point users at site/index.html as the entry point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Add 津ICP备13004281号-4 to the footer of every site page.
- Fix a malformed li tag in site/roundtable.html.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Rewrite site/index.html as a product marketing page for jcode (AI coding companion)
- Add hero terminal mockup, feature grid, desktop download section, CLI section
- Link to GitHub and actual docs/docs/ (copied from repo docs/_site with /jcode/ → /docs/ rewrite)
- Rebuild showcase.html with per-demo Maximize modal and Open-in-new-window links
- Remove eval/report/test pages from the site nav (report, findings, roundtable, docs.html)
- Add Chinese ICP footer to all pages

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a new agent-eval subsystem: a Go headless ACP test harness, a Python orchestration/verification/analysis pipeline for autonomous jcode evaluation, generated reports/findings/roundtable artifacts, a full Just-the-Docs documentation site, and a marketing/showcase site with several standalone frontend demo projects.

Changes

Evaluation Harness Core

Layer / File(s) Summary
README and gitignore
agent-eval/README.md, agent-eval/.gitignore
Documents the harness design, isolation strategy, and repo layout; ignores generated run artifacts and caches.
Go ACP harness
agent-eval/harness/go.mod, agent-eval/harness/main.go
Implements a headless harness that drives one ACP prompt turn, auto-approves permissions, records event streams, and outputs structured results.
Test cases and oracles
agent-eval/suite/testcases.json, agent-eval/suite/verify.py
Defines test cases with fixtures/oracles and implements deterministic verifiers checking sandbox state and trajectory.
Orchestrator
agent-eval/suite/orchestrate.py
Isolates per-run HOME/sandbox, runs the harness under timeout, applies oracles and contract checks, and writes per-run/aggregate records.
Analysis and report generation
agent-eval/analysis/analyze.py, agent-eval/analysis/report.py, agent-eval/analysis/findings.json, agent-eval/roundtable/roundtable.json
Aggregates run records into metrics and renders a self-contained HTML report combining analysis, findings, and roundtable content.
Generated report artifacts
agent-eval/report/analysis.json, agent-eval/report/report.html
Provides generated analysis output and rendered report for a completed evaluation run.

Documentation Site, Showcase, and Frontend Demo Projects

Layer / File(s) Summary
Just-the-Docs theme assets
agent-eval/site/docs/assets/...
Adds theme CSS/JS and search index used across documentation pages.
Documentation pages
agent-eval/site/docs/*.html, agent-eval/site/docs/overview/*, agent-eval/site/docs/tools/*
Adds content pages covering getting started, configuration, commands, overview topics, tools, and web interface.
Site homepage and shared styling
agent-eval/site/index.html, agent-eval/site/css/style.css, agent-eval/site/js/site.js
Adds the marketing homepage and shared stylesheet/script.
Showcase page and generator
agent-eval/site/showcase.html, agent-eval/showcase/index.html, agent-eval/showcase/generate_data.py, agent-eval/showcase/data.json
Adds a modal gallery page and a generator that selects/copies best demo runs into showcase data.
Frontend demo projects
agent-eval/showcase/projects/*, agent-eval/site/projects/*
Adds standalone demo HTML apps (analytics dashboard, canvas particles, landing hero, pricing calculator, SVG dataviz, to-do app).

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Orchestrator as orchestrate.py
  participant Home as isolated HOME
  participant Harness as jcode-acp-harness
  participant Agent as jcode acp
  participant Verify as verify.py
  Orchestrator->>Home: build_home() + seed_fixtures()
  Orchestrator->>Harness: run_one() spawns subprocess with timeout
  Harness->>Agent: Initialize, NewSession, Prompt
  Agent-->>Harness: SessionUpdate events, StopReason
  Harness-->>Orchestrator: result.json + events.jsonl
  Orchestrator->>Verify: verify_case(oracles)
  Verify-->>Orchestrator: pass/fail per oracle
  Orchestrator->>Orchestrator: contract_checks() + record.json
  Orchestrator->>Orchestrator: all_records.json aggregation
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the agent-eval showcase work, though it under-describes the broader harness and documentation changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-eval-showcase

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (11)
agent-eval/analysis/analyze.py (3)

29-37: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Silently dropped malformed record.json files skew aggregate stats.

except Exception: pass drops runs with unparseable record.json with no trace, so total_runs/pass-rate/CI in the final report can silently exclude failed runs without anyone knowing why counts don't match expectations.

🩹 Suggested fix
     for rd in sorted(Path(runs_dir).glob("*/record.json")):
         try:
             recs.append(json.loads(rd.read_text()))
             recs[-1]["_dir"] = str(rd.parent)
-        except Exception:
-            pass
+        except Exception as e:
+            print(f"warn: failed to load {rd}: {e}")
     return recs
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/analysis/analyze.py` around lines 29 - 37, The load_records
function is swallowing every exception while parsing record.json, which hides
malformed runs and skews the aggregate stats. Update load_records to handle json
parsing failures explicitly and emit a warning or error that includes the run
directory from rd.parent before skipping that record. Keep the _dir tagging for
successfully parsed entries so the final report can still trace which runs were
included.

Source: Linters/SAST tools


40-62: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Malformed event lines silently dropped in loop detection.

Same swallow-and-continue pattern (Ruff S112/BLE001) — a corrupted/truncated events.jsonl line silently reduces the loop-detection signal to 0 instead of flagging the run as suspect, undermining the very trustworthiness this harness is built to provide.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/analysis/analyze.py` around lines 40 - 62, The malformed
`events.jsonl` parsing in `detect_loops` is silently swallowing corrupted lines,
which can hide loop signals and make a bad run look clean. Update `detect_loops`
so JSON decode failures are not ignored; either surface the parse error or mark
the run as suspect while preserving the existing loop-count logic for valid
`session_update` / `tool_call` entries. Use the `detect_loops` function and its
`events.jsonl` read loop as the location to adjust the error handling.

Source: Linters/SAST tools


87-99: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Fuzzy substring model-id matching in est_cost can attribute wrong pricing.

if k in model or model in k matches on substring containment, so e.g. a pricing entry for "gpt-4" would also match "gpt-4o-mini" or vice versa, silently attaching an incorrect price. Since the docstring already flags this as "best-effort," this is low priority, but consider anchoring the match (e.g., exact suffix segment match) to avoid silent cost misattribution as more models are added.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/analysis/analyze.py` around lines 87 - 99, The fuzzy fallback
matching in est_cost can select the wrong pricing entry because it uses
substring containment between the pricing key and the model id. Update the
matching logic in est_cost to prefer exact matches and, for fallback, only use a
stricter anchored/suffix-segment comparison so models like gpt-4 and gpt-4o-mini
do not cross-match. Keep the change localized to est_cost and its pricing lookup
loop.
agent-eval/analysis/report.py (2)

40-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate JSONL event-parsing logic vs. analyze.py.detect_loops.

Both render_trajectory here and detect_loops in agent-eval/analysis/analyze.py implement near-identical "read events.jsonl → skip blank/unparsable lines → filter kind == session_update" loops, with the same silent except/continue pattern. Consider extracting a shared iter_session_updates(rundir) helper (e.g. in a small events.py module) used by both scripts to avoid drift between the two consumers of the same event-stream contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/analysis/report.py` around lines 40 - 62, The event-stream parsing
logic in render_trajectory duplicates the same events.jsonl scanning pattern
used by detect_loops, so move the shared “read/skip/parse/filter session_update”
behavior into a common helper such as iter_session_updates in a shared module.
Update render_trajectory and detect_loops to consume that helper instead of
maintaining separate silent try/continue loops, keeping the events.jsonl
contract in one place.

64-71: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Silent parse-error swallowing in the report's trajectory renderer.

Same broad except Exception: continue (Ruff S112/BLE001) as analyze.py.detect_loops — a corrupted event line silently truncates the rendered trajectory shown in the public showcase without any indication.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/analysis/report.py` around lines 64 - 71, The trajectory reader in
report.py is silently swallowing JSON parse failures in the loop that reads ev
lines, which can hide corrupted event data and truncate the rendered output.
Update the parsing in the same read_text/json.loads flow to avoid a broad except
Exception and instead handle decode errors explicitly in the renderer path,
logging or surfacing the bad line while continuing only when that behavior is
intentional. Use the surrounding trajectory rendering logic in the report module
to keep the failure visible rather than silently ignored.

Source: Linters/SAST tools

agent-eval/site/showcase.html (1)

66-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded PROJECTS array duplicates the generator's data contract.

PROJECTS (ids/titles/descriptions) is hand-maintained here, duplicating META in generate_data.py and the generated showcase/data.json. If the eval batch is rerun with different descriptions or a new frontend case is added, this file will silently drift out of sync since it never reads data.json.

Consider fetching ../showcase/data.json (or a site-local copy) at load time and building the list from the projects array instead of hardcoding it, so this page always reflects the latest generated results.

Copies that run's index.html into showcase/projects/<case_id>/ and writes showcase/data.json with per-project metadata + aggregate metrics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/site/showcase.html` around lines 66 - 113, The hardcoded PROJECTS
list in the showcase page duplicates the generated data contract and can drift
from the latest batch output. Update the logic around PROJECTS/openModal and the
projects rendering block to load and build entries from showcase/data.json (or a
local equivalent) instead of embedding ids/titles/descriptions inline. Use the
fetched projects array to populate the cards, iframe srcs, and modal actions so
the page always stays in sync with generate_data.py output.
agent-eval/site/projects/fe_landing_hero/index.html (1)

1-456: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Keep the site and showcase project copies in sync. agent-eval/showcase/generate_data.py only writes showcase/projects/<case_id>/index.html, while site/projects/<case_id>/index.html is maintained separately. If both are meant to stay mirrored, have the generator update both paths or derive one from the other so regenerations don't drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/site/projects/fe_landing_hero/index.html` around lines 1 - 456,
The site and showcase copies are drifting because this landing page exists
separately from the generated showcase copy. Update the generation flow so the
same source content populates both copies, either by writing to both output
paths or by making one path consume the other, and keep the shared landing page
markup in sync in this index.html so regenerations do not diverge.
agent-eval/showcase/projects/fe_analytics_dashboard/index.html (1)

1-767: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Duplicated demo asset across showcase/projects and site/projects.

This file is byte-for-byte duplicated at agent-eval/site/projects/fe_analytics_dashboard/index.html, and the same pattern repeats across all 6 demo projects (12 files total). Any future fix or tweak to a demo must be applied twice, and the two copies will silently drift if only one is updated (as already partially observed with META/PROJECTS display data). Consider a small build/sync step (or symlinks, if the deployment target supports it) that generates both output locations from one canonical source.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/showcase/projects/fe_analytics_dashboard/index.html` around lines
1 - 767, The issue is that the same demo asset is maintained in both showcase
and site outputs, which will drift over time. Update the build/publish flow for
the affected demo pages (including the fe_analytics_dashboard index.html) so
both locations are generated from one canonical source instead of being edited
separately. If you keep both outputs, add a sync step or shared source path for
all demo project files so future changes automatically propagate to both trees.
agent-eval/showcase/generate_data.py (2)

22-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Frontend cases missing from META are silently dropped.

The loop only iterates META.items(), so any case_id present in all_records.json under tier frontend but absent from META is silently excluded from data.json with no warning. If a new frontend test case is added to testcases.json without a corresponding META entry, it disappears from the showcase without anyone noticing.

Consider logging unmatched case_ids so drift between testcases.json and META is caught early.

♻️ Suggested diff
     runs_n = len(fe)
     pass_n = sum(1 for r in fe if r.get("task_passed"))
+    known_ids = set(META.keys())
+    unmatched = {r["case_id"] for r in fe} - known_ids
+    if unmatched:
+        print(f"warning: frontend case_ids not in META, skipped: {sorted(unmatched)}")

Also applies to: 78-101

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/showcase/generate_data.py` around lines 22 - 47, The frontend
showcase generation in generate_data.py is silently skipping any frontend
case_id that exists in all_records.json but not in META. Update the logic around
the META-driven iteration to detect unmatched frontend case_ids and emit a
warning or log entry when testcases.json/all_records.json contains cases not
present in META, using the existing generate_data.py flow so drift is visible
during data generation.

1-119: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

showcase/data.json is dead output showcase/index.html only redirects to ../site/showcase.html, and site/showcase.html hardcodes its own PROJECTS list. Either have the page read the generated JSON or stop writing it to avoid the two lists drifting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/showcase/generate_data.py` around lines 1 - 119, The generated
showcase metadata is not being used because showcase/index.html redirects to
site/showcase.html, which hardcodes its own PROJECTS list, so generate_data.py
is producing dead output. Update the showcase flow so the page reads the
generated data.json (using the logic around main() and the projects payload) or
remove the data.json write entirely if the site will keep a static PROJECTS
list, and make the source of truth consistent to avoid drift.
agent-eval/site/docs/assets/js/just-the-docs.js (1)

1-602: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Vendored Just-the-Docs theme script — static analysis findings are largely false positives here.

This is the stock Just-the-Docs just-the-docs.js asset (unmodified vendor code). The innerHTML XSS warnings operate on doc.title/doc.content sourced from the site's own build-time search-data.json (not user input), the "SQL injection" hit on index.query(...) is a lunr.js full-text query API being misclassified, and the "React useState" hits on setTimeout calls are unrelated to this vanilla-JS file — all safe to disregard.

The var active/var next declarations inside switch cases (flagged by Biome at Lines 422, 433, 449) are a legitimate lint concern in isolation, but since var is function-scoped (not block-scoped), there's no actual cross-case leakage bug here — just a style nit in vendored code that typically shouldn't be hand-edited.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/site/docs/assets/js/just-the-docs.js` around lines 1 - 602, This
is vendored Just-the-Docs code, so the XSS and lunr-related findings in
`initSearch`/`searchLoaded` should be treated as false positives and not changed
in the asset itself. If Biome still needs a cleanup, address only the `var
active`/`var next` declarations in the `searchInput` keydown switch by scoping
them safely within each case or by wrapping the cases in blocks, while leaving
the rest of the vendor script untouched.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agent-eval/analysis/report.py`:
- Around line 57-117: `render_trajectory` is rendering tool-call `rawInput` and
`rawOutput` directly into the report, which leaks host-specific details like
absolute filesystem paths and usernames. Add sanitization/redaction in
`render_trajectory` before building `rows` so tool I/O is normalized and
sensitive path-like or environment-specific values are removed or replaced with
placeholders, while keeping the HTML escaping in place. Use the existing
`render_trajectory` flow and the `rawInput`/`rawOutput` handling branches as the
place to apply the redaction.

In `@agent-eval/harness/main.go`:
- Around line 201-352: The main harness flow in main() lacks signal handling, so
an external SIGTERM/SIGINT can terminate the harness before subCancel() and
cmd.Wait() run, leaving the jcode acp subprocess orphaned. Add a
signal.Notify-based handler in main() that listens for termination signals,
cancels the subprocess context (subCtx via subCancel), and records a terminal
HARNESS_ERROR/TIMEOUT-style result before exiting. Make sure the cleanup path
still reaches the exec.CommandContext, conn.Cancel, and result finalization
logic even when interrupted.
- Around line 82-85: The client struct has an unused sandbox field that will
trip the unused linter. Remove client.sandbox from the struct and any
construction/assignment in the client initialization path, or wire it into an
actual read in the client methods if it is meant to be used; check the client
type and its constructor/setup code to keep the fields consistent.
- Around line 297-333: The timeout handling in the Prompt flow can still hang
because the best-effort `conn.Cancel` call uses an unbounded
`context.Background()`. Update the timeout branch in `main.go` so the graceful
cancel uses a short bounded context (or reuses the existing `promptCtx` budget)
before the later `subCancel()`/`cmd.Wait()` cleanup, and keep the change
localized around the `conn.Prompt`/`conn.Cancel` timeout path.

In `@agent-eval/README.md`:
- Around line 70-77: The reproduction steps in README use analyze.py and
report.py with an output path that lands in the git-ignored runs directory
instead of the checked-in report artifact location. Update the documented
command, or align analyze.py’s --out default, so the generated analysis.json
matches the expected agent-eval/report/analysis.json path used by the generated
analysis/report artifacts and the report.py invocation.

In `@agent-eval/site/docs/assets/css/just-the-docs-head-nav.css`:
- Line 1: The just-the-docs-head-nav stylesheet asset is being generated as a
full HTML document instead of CSS, so fix the build/export step that writes this
file and ensure it emits only valid stylesheet rules. Use the asset target
referenced by just-the-docs-head-nav.css and verify the output matches the other
CSS assets in the same directory, with no HTML head/body markup or embedded page
content.

In `@agent-eval/site/docs/configuration.html`:
- Line 1: The Configuration page has a broken relative link for MCP Integration
in the `mcp_servers` section. Update the anchor in the configuration docs to
point to the actual MCP page path used elsewhere in the file, matching the
`Overview`/`MCP Integration` nav target. Use the surrounding `mcp_servers`
documentation block and the `MCP Integration` link text to locate and replace
the incorrect href so it resolves correctly from `configuration.html`.

In `@agent-eval/site/docs/get-started.html`:
- Line 1: The install command in the Get Started docs uses the wrong Go module
path, pointing to cnjack/docs instead of the actual jcode repository. Update the
install instruction in the Get Started page to use the same repository path as
the later git clone guidance, so the command resolves the correct module for
jcode.

In `@agent-eval/site/showcase.html`:
- Line 61: The footer contains stray ICP registration boilerplate that appears
unrelated to this site. Remove the hardcoded ICP text from the footer content in
the showcase page markup so only relevant project/footer information remains,
and keep the affected footer element consistent with the rest of the page
structure.

In `@agent-eval/suite/orchestrate.py`:
- Around line 61-76: The per-run HOME setup is persisting live provider
credentials in config.json via build_home, and _prune_home is keeping that file
after the run. Update build_home to redact or omit the providers block when
writing the run-local config, or add a post-run cleanup step in _prune_home to
strip secrets before preserving config.json. Keep only the data needed by
analyze.py and report.py (usage, sessions, debug.log), and ensure the final
persisted config no longer contains API keys.

---

Nitpick comments:
In `@agent-eval/analysis/analyze.py`:
- Around line 29-37: The load_records function is swallowing every exception
while parsing record.json, which hides malformed runs and skews the aggregate
stats. Update load_records to handle json parsing failures explicitly and emit a
warning or error that includes the run directory from rd.parent before skipping
that record. Keep the _dir tagging for successfully parsed entries so the final
report can still trace which runs were included.
- Around line 40-62: The malformed `events.jsonl` parsing in `detect_loops` is
silently swallowing corrupted lines, which can hide loop signals and make a bad
run look clean. Update `detect_loops` so JSON decode failures are not ignored;
either surface the parse error or mark the run as suspect while preserving the
existing loop-count logic for valid `session_update` / `tool_call` entries. Use
the `detect_loops` function and its `events.jsonl` read loop as the location to
adjust the error handling.
- Around line 87-99: The fuzzy fallback matching in est_cost can select the
wrong pricing entry because it uses substring containment between the pricing
key and the model id. Update the matching logic in est_cost to prefer exact
matches and, for fallback, only use a stricter anchored/suffix-segment
comparison so models like gpt-4 and gpt-4o-mini do not cross-match. Keep the
change localized to est_cost and its pricing lookup loop.

In `@agent-eval/analysis/report.py`:
- Around line 40-62: The event-stream parsing logic in render_trajectory
duplicates the same events.jsonl scanning pattern used by detect_loops, so move
the shared “read/skip/parse/filter session_update” behavior into a common helper
such as iter_session_updates in a shared module. Update render_trajectory and
detect_loops to consume that helper instead of maintaining separate silent
try/continue loops, keeping the events.jsonl contract in one place.
- Around line 64-71: The trajectory reader in report.py is silently swallowing
JSON parse failures in the loop that reads ev lines, which can hide corrupted
event data and truncate the rendered output. Update the parsing in the same
read_text/json.loads flow to avoid a broad except Exception and instead handle
decode errors explicitly in the renderer path, logging or surfacing the bad line
while continuing only when that behavior is intentional. Use the surrounding
trajectory rendering logic in the report module to keep the failure visible
rather than silently ignored.

In `@agent-eval/showcase/generate_data.py`:
- Around line 22-47: The frontend showcase generation in generate_data.py is
silently skipping any frontend case_id that exists in all_records.json but not
in META. Update the logic around the META-driven iteration to detect unmatched
frontend case_ids and emit a warning or log entry when
testcases.json/all_records.json contains cases not present in META, using the
existing generate_data.py flow so drift is visible during data generation.
- Around line 1-119: The generated showcase metadata is not being used because
showcase/index.html redirects to site/showcase.html, which hardcodes its own
PROJECTS list, so generate_data.py is producing dead output. Update the showcase
flow so the page reads the generated data.json (using the logic around main()
and the projects payload) or remove the data.json write entirely if the site
will keep a static PROJECTS list, and make the source of truth consistent to
avoid drift.

In `@agent-eval/showcase/projects/fe_analytics_dashboard/index.html`:
- Around line 1-767: The issue is that the same demo asset is maintained in both
showcase and site outputs, which will drift over time. Update the build/publish
flow for the affected demo pages (including the fe_analytics_dashboard
index.html) so both locations are generated from one canonical source instead of
being edited separately. If you keep both outputs, add a sync step or shared
source path for all demo project files so future changes automatically propagate
to both trees.

In `@agent-eval/site/docs/assets/js/just-the-docs.js`:
- Around line 1-602: This is vendored Just-the-Docs code, so the XSS and
lunr-related findings in `initSearch`/`searchLoaded` should be treated as false
positives and not changed in the asset itself. If Biome still needs a cleanup,
address only the `var active`/`var next` declarations in the `searchInput`
keydown switch by scoping them safely within each case or by wrapping the cases
in blocks, while leaving the rest of the vendor script untouched.

In `@agent-eval/site/projects/fe_landing_hero/index.html`:
- Around line 1-456: The site and showcase copies are drifting because this
landing page exists separately from the generated showcase copy. Update the
generation flow so the same source content populates both copies, either by
writing to both output paths or by making one path consume the other, and keep
the shared landing page markup in sync in this index.html so regenerations do
not diverge.

In `@agent-eval/site/showcase.html`:
- Around line 66-113: The hardcoded PROJECTS list in the showcase page
duplicates the generated data contract and can drift from the latest batch
output. Update the logic around PROJECTS/openModal and the projects rendering
block to load and build entries from showcase/data.json (or a local equivalent)
instead of embedding ids/titles/descriptions inline. Use the fetched projects
array to populate the cards, iframe srcs, and modal actions so the page always
stays in sync with generate_data.py output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6ce7d758-e99f-4cb4-b6ac-efe25a0a54f4

📥 Commits

Reviewing files that changed from the base of the PR and between 22fecba and fbd54d0.

⛔ Files ignored due to path filters (5)
  • agent-eval/harness/go.sum is excluded by !**/*.sum
  • agent-eval/site/docs/assets/css/just-the-docs-dark.css.map is excluded by !**/*.map
  • agent-eval/site/docs/assets/css/just-the-docs-default.css.map is excluded by !**/*.map
  • agent-eval/site/docs/assets/css/just-the-docs-light.css.map is excluded by !**/*.map
  • agent-eval/site/docs/assets/js/vendor/lunr.min.js is excluded by !**/*.min.js
📒 Files selected for processing (59)
  • agent-eval/.gitignore
  • agent-eval/README.md
  • agent-eval/analysis/analyze.py
  • agent-eval/analysis/findings.json
  • agent-eval/analysis/report.py
  • agent-eval/harness/go.mod
  • agent-eval/harness/main.go
  • agent-eval/report/analysis.json
  • agent-eval/report/report.html
  • agent-eval/roundtable/roundtable.json
  • agent-eval/showcase/data.json
  • agent-eval/showcase/generate_data.py
  • agent-eval/showcase/index.html
  • agent-eval/showcase/projects/fe_analytics_dashboard/index.html
  • agent-eval/showcase/projects/fe_canvas_particles/index.html
  • agent-eval/showcase/projects/fe_landing_hero/index.html
  • agent-eval/showcase/projects/fe_pricing_calculator/index.html
  • agent-eval/showcase/projects/fe_svg_dataviz/index.html
  • agent-eval/showcase/projects/fe_todo_app/index.html
  • agent-eval/site/css/style.css
  • agent-eval/site/docs/assets/css/just-the-docs-dark.css
  • agent-eval/site/docs/assets/css/just-the-docs-default.css
  • agent-eval/site/docs/assets/css/just-the-docs-head-nav.css
  • agent-eval/site/docs/assets/css/just-the-docs-light.css
  • agent-eval/site/docs/assets/js/just-the-docs.js
  • agent-eval/site/docs/assets/js/search-data.json
  • agent-eval/site/docs/commands.html
  • agent-eval/site/docs/configuration.html
  • agent-eval/site/docs/get-started.html
  • agent-eval/site/docs/index.html
  • agent-eval/site/docs/overview.html
  • agent-eval/site/docs/overview/agent-teams.html
  • agent-eval/site/docs/overview/agent.html
  • agent-eval/site/docs/overview/context-memory.html
  • agent-eval/site/docs/overview/mcp.html
  • agent-eval/site/docs/overview/models.html
  • agent-eval/site/docs/overview/plan-mode.html
  • agent-eval/site/docs/overview/sessions.html
  • agent-eval/site/docs/overview/skills.html
  • agent-eval/site/docs/overview/ssh.html
  • agent-eval/site/docs/overview/subagents.html
  • agent-eval/site/docs/tools.html
  • agent-eval/site/docs/tools/execute.html
  • agent-eval/site/docs/tools/file-tools.html
  • agent-eval/site/docs/tools/search-tools.html
  • agent-eval/site/docs/tools/task-management.html
  • agent-eval/site/docs/web-interface.html
  • agent-eval/site/index.html
  • agent-eval/site/js/site.js
  • agent-eval/site/projects/fe_analytics_dashboard/index.html
  • agent-eval/site/projects/fe_canvas_particles/index.html
  • agent-eval/site/projects/fe_landing_hero/index.html
  • agent-eval/site/projects/fe_pricing_calculator/index.html
  • agent-eval/site/projects/fe_svg_dataviz/index.html
  • agent-eval/site/projects/fe_todo_app/index.html
  • agent-eval/site/showcase.html
  • agent-eval/suite/orchestrate.py
  • agent-eval/suite/testcases.json
  • agent-eval/suite/verify.py

Comment on lines +57 to +117
def render_trajectory(rundir):
ev = Path(rundir) / "events.jsonl"
if not ev.exists():
return "<p class='muted'>no event log</p>"
calls = {}
order = []
final = []
for line in ev.read_text(errors="ignore").splitlines():
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
except Exception:
continue
if d.get("kind") != "session_update":
continue
u = d.get("data", {})
su = u.get("sessionUpdate")
if su == "tool_call":
tid = u.get("toolCallId")
calls[tid] = {"title": u.get("title", ""), "kind": u.get("kind", "other"),
"input": u.get("rawInput"), "status": u.get("status", ""),
"output": None}
order.append(tid)
elif su == "tool_call_update":
tid = u.get("toolCallId")
if tid in calls:
if u.get("status"):
calls[tid]["status"] = u["status"]
if u.get("rawOutput") is not None:
calls[tid]["output"] = u["rawOutput"]
elif su == "agent_message_chunk":
t = (u.get("content") or {}).get("text")
if t:
final.append(t)
rows = []
for i, tid in enumerate(order, 1):
c = calls[tid]
icon = KIND_ICON.get(c["kind"], "🔧")
inp = json.dumps(c["input"])[:160] if c["input"] is not None else ""
out = c["output"]
if isinstance(out, (dict, list)):
out = json.dumps(out)
out = (str(out)[:180] if out is not None else "")
stat = c["status"]
stat_c = {"completed": "#73d13d", "failed": "#ff4d4f", "in_progress": "#ffc53d"}.get(stat, "#888")
rows.append(f"""
<div class="tstep">
<div class="tnum">{i}</div>
<div class="tbody">
<div class="ttitle">{icon} <b>{esc(c['title'])}</b>
<span class="tstat" style="color:{stat_c}">{esc(stat)}</span></div>
{f'<div class="tio">→ {esc(inp)}</div>' if inp else ''}
{f'<div class="tio out">← {esc(out)}</div>' if out else ''}
</div>
</div>""")
finaltext = esc("".join(final))[:1200]
return f"""<div class="traj">{''.join(rows)}
<div class="tfinal"><div class="tfinal-h">final answer</div>{finaltext}</div></div>"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Tool-call rawInput/rawOutput are rendered verbatim, leaking local filesystem paths and a real username into the report.

render_trajectory HTML-escapes but does not sanitize rawInput/rawOutput before embedding them. The generated agent-eval/report/report.html in this PR shows full absolute paths like /private/tmp/claude-501/-Users-jack-workpath-jjj-jcode/..., exposing the developer's real machine username. Since this report is designed to feed the public showcase/marketing site (per the PR stack), shipping raw host paths (and any other environment specifics captured in tool I/O) in a public artifact is a privacy leak that should be redacted before rendering.

🔒 Suggested mitigation
+import re
+
+_HOME_PATH_RE = re.compile(r"/(?:Users|home)/[^/\s\"]+")
+
+def _redact(s):
+    return _HOME_PATH_RE.sub("~", s) if isinstance(s, str) else s
+
 def render_trajectory(rundir):
     ...
-        inp = json.dumps(c["input"])[:160] if c["input"] is not None else ""
+        inp = _redact(json.dumps(c["input"]))[:160] if c["input"] is not None else ""
         out = c["output"]
         if isinstance(out, (dict, list)):
             out = json.dumps(out)
-        out = (str(out)[:180] if out is not None else "")
+        out = _redact(str(out))[:180] if out is not None else ""
📝 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.

Suggested change
def render_trajectory(rundir):
ev = Path(rundir) / "events.jsonl"
if not ev.exists():
return "<p class='muted'>no event log</p>"
calls = {}
order = []
final = []
for line in ev.read_text(errors="ignore").splitlines():
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
except Exception:
continue
if d.get("kind") != "session_update":
continue
u = d.get("data", {})
su = u.get("sessionUpdate")
if su == "tool_call":
tid = u.get("toolCallId")
calls[tid] = {"title": u.get("title", ""), "kind": u.get("kind", "other"),
"input": u.get("rawInput"), "status": u.get("status", ""),
"output": None}
order.append(tid)
elif su == "tool_call_update":
tid = u.get("toolCallId")
if tid in calls:
if u.get("status"):
calls[tid]["status"] = u["status"]
if u.get("rawOutput") is not None:
calls[tid]["output"] = u["rawOutput"]
elif su == "agent_message_chunk":
t = (u.get("content") or {}).get("text")
if t:
final.append(t)
rows = []
for i, tid in enumerate(order, 1):
c = calls[tid]
icon = KIND_ICON.get(c["kind"], "🔧")
inp = json.dumps(c["input"])[:160] if c["input"] is not None else ""
out = c["output"]
if isinstance(out, (dict, list)):
out = json.dumps(out)
out = (str(out)[:180] if out is not None else "")
stat = c["status"]
stat_c = {"completed": "#73d13d", "failed": "#ff4d4f", "in_progress": "#ffc53d"}.get(stat, "#888")
rows.append(f"""
<div class="tstep">
<div class="tnum">{i}</div>
<div class="tbody">
<div class="ttitle">{icon} <b>{esc(c['title'])}</b>
<span class="tstat" style="color:{stat_c}">{esc(stat)}</span></div>
{f'<div class="tio">→ {esc(inp)}</div>' if inp else ''}
{f'<div class="tio out">← {esc(out)}</div>' if out else ''}
</div>
</div>""")
finaltext = esc("".join(final))[:1200]
return f"""<div class="traj">{''.join(rows)}
<div class="tfinal"><div class="tfinal-h">final answer</div>{finaltext}</div></div>"""
import re
_HOME_PATH_RE = re.compile(r"/(?:Users|home)/[^/\s\"]+")
def _redact(s):
return _HOME_PATH_RE.sub("~", s) if isinstance(s, str) else s
def render_trajectory(rundir):
ev = Path(rundir) / "events.jsonl"
if not ev.exists():
return "<p class='muted'>no event log</p>"
calls = {}
order = []
final = []
for line in ev.read_text(errors="ignore").splitlines():
line = line.strip()
if not line:
continue
try:
d = json.loads(line)
except Exception:
continue
if d.get("kind") != "session_update":
continue
u = d.get("data", {})
su = u.get("sessionUpdate")
if su == "tool_call":
tid = u.get("toolCallId")
calls[tid] = {"title": u.get("title", ""), "kind": u.get("kind", "other"),
"input": u.get("rawInput"), "status": u.get("status", ""),
"output": None}
order.append(tid)
elif su == "tool_call_update":
tid = u.get("toolCallId")
if tid in calls:
if u.get("status"):
calls[tid]["status"] = u["status"]
if u.get("rawOutput") is not None:
calls[tid]["output"] = u["rawOutput"]
elif su == "agent_message_chunk":
t = (u.get("content") or {}).get("text")
if t:
final.append(t)
rows = []
for i, tid in enumerate(order, 1):
c = calls[tid]
icon = KIND_ICON.get(c["kind"], "🔧")
inp = _redact(json.dumps(c["input"]))[:160] if c["input"] is not None else ""
out = c["output"]
if isinstance(out, (dict, list)):
out = json.dumps(out)
out = _redact(str(out))[:180] if out is not None else ""
stat = c["status"]
stat_c = {"completed": "`#73d13d`", "failed": "`#ff4d4f`", "in_progress": "`#ffc53d`"}.get(stat, "`#888`")
rows.append(f"""
<div class="tstep">
<div class="tnum">{i}</div>
<div class="tbody">
<div class="ttitle">{icon} <b>{esc(c['title'])}</b>
<span class="tstat" style="color:{stat_c}">{esc(stat)}</span></div>
{f'<div class="tio">→ {esc(inp)}</div>' if inp else ''}
{f'<div class="tio out">← {esc(out)}</div>' if out else ''}
</div>
</div>""")
finaltext = esc("".join(final))[:1200]
return f"""<div class="traj">{''.join(rows)}
<div class="tfinal"><div class="tfinal-h">final answer</div>{finaltext}</div></div>"""
🧰 Tools
🪛 ast-grep (0.44.0)

[info] 96-96: use jsonify instead of json.dumps for JSON output
Context: json.dumps(c["input"])
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 99-99: use jsonify instead of json.dumps for JSON output
Context: json.dumps(out)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 Ruff (0.15.20)

[error] 70-71: try-except-continue detected, consider logging the exception

(S112)


[warning] 70-70: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/analysis/report.py` around lines 57 - 117, `render_trajectory` is
rendering tool-call `rawInput` and `rawOutput` directly into the report, which
leaks host-specific details like absolute filesystem paths and usernames. Add
sanitization/redaction in `render_trajectory` before building `rows` so tool I/O
is normalized and sensitive path-like or environment-specific values are removed
or replaced with placeholders, while keeping the HTML escaping in place. Use the
existing `render_trajectory` flow and the `rawInput`/`rawOutput` handling
branches as the place to apply the redaction.

Comment on lines +82 to +85
type client struct {
rec *recorder
sandbox string
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Unused sandbox field.

client.sandbox is written at construction but never read. Given .golangci.yml enforces the unused linter, this is likely to fail CI as-is.

♻️ Proposed fix
 type client struct {
 	rec     *recorder
-	sandbox string
 }
-	conn := acp.NewClientSideConnection(&client{rec: rec, sandbox: *cwd}, stdin, stdout)
+	conn := acp.NewClientSideConnection(&client{rec: rec}, stdin, stdout)

Also applies to: 262-262

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/harness/main.go` around lines 82 - 85, The client struct has an
unused sandbox field that will trip the unused linter. Remove client.sandbox
from the struct and any construction/assignment in the client initialization
path, or wire it into an actual read in the client methods if it is meant to be
used; check the client type and its constructor/setup code to keep the fields
consistent.

Comment on lines +201 to +352
func main() {
var (
bin = flag.String("bin", "", "path to jcode binary")
cwd = flag.String("cwd", "", "session working directory (sandbox, absolute)")
promptStr = flag.String("prompt", "", "prompt text (or use -promptfile)")
promptFile = flag.String("promptfile", "", "file containing the prompt text")
outPath = flag.String("out", "events.jsonl", "event log output path")
model = flag.String("model", "", "model label recorded in the result")
modeStr = flag.String("mode", "full_access", "session mode: approval|plan|full_access")
timeoutSec = flag.Int("timeout", 300, "prompt turn timeout in seconds")
setupSec = flag.Int("setup-timeout", 90, "initialize+new-session timeout in seconds")
)
flag.Parse()

if *promptFile != "" {
b, err := os.ReadFile(*promptFile)
if err != nil {
die(map[string]any{"stop_reason": "HARNESS_ERROR", "error": "read promptfile: " + err.Error(), "model": *model})
}
*promptStr = string(b)
}
if *bin == "" || *cwd == "" || *promptStr == "" {
die(map[string]any{"stop_reason": "HARNESS_ERROR", "error": "missing -bin/-cwd/-prompt", "model": *model})
}

f, err := os.Create(*outPath)
if err != nil {
die(map[string]any{"stop_reason": "HARNESS_ERROR", "error": "create out: " + err.Error(), "model": *model})
}
defer f.Close()
rec := newRecorder(f)

result := map[string]any{"model": *model, "cwd": *cwd, "mode": *modeStr}
start := time.Now()

// Launch the jcode ACP server. HOME/env is inherited from the caller, which
// is expected to have already pointed HOME at an isolated throwaway dir.
subCtx, subCancel := context.WithCancel(context.Background())
defer subCancel()
cmd := exec.CommandContext(subCtx, *bin, "acp")
cmd.Env = os.Environ()
cmd.Dir = *cwd
stdin, err := cmd.StdinPipe()
if err != nil {
finish(rec, result, "HARNESS_ERROR", "stdin pipe: "+err.Error(), start)
return
}
stdout, err := cmd.StdoutPipe()
if err != nil {
finish(rec, result, "HARNESS_ERROR", "stdout pipe: "+err.Error(), start)
return
}
if stderrF, ferr := os.Create(*outPath + ".stderr"); ferr == nil {
cmd.Stderr = stderrF
defer stderrF.Close()
}
if err := cmd.Start(); err != nil {
finish(rec, result, "HARNESS_ERROR", "start jcode: "+err.Error(), start)
return
}

conn := acp.NewClientSideConnection(&client{rec: rec, sandbox: *cwd}, stdin, stdout)

// Phase 1: initialize + new session, under a setup timeout.
setupCtx, setupCancel := context.WithTimeout(context.Background(), time.Duration(*setupSec)*time.Second)
defer setupCancel()

initResp, err := conn.Initialize(setupCtx, acp.InitializeRequest{
ProtocolVersion: acp.ProtocolVersionNumber,
ClientInfo: &acp.Implementation{Name: "jcode-acp-harness", Version: "0.1.0"},
})
if err != nil {
subCancel()
_ = cmd.Wait()
finish(rec, result, "INIT_ERROR", "initialize: "+err.Error(), start)
return
}
rec.line("initialized", initResp)

ns, err := conn.NewSession(setupCtx, acp.NewSessionRequest{Cwd: *cwd, McpServers: []acp.McpServer{}})
if err != nil {
subCancel()
_ = cmd.Wait()
finish(rec, result, "NEWSESSION_ERROR", "new session: "+err.Error(), start)
return
}
sid := ns.SessionId
result["sessionId"] = string(sid)
rec.line("session_new", map[string]any{"sessionId": string(sid)})

if *modeStr != "" {
if _, merr := conn.SetSessionMode(setupCtx, acp.SetSessionModeRequest{SessionId: sid, ModeId: acp.SessionModeId(*modeStr)}); merr != nil {
rec.line("setmode_error", map[string]any{"err": merr.Error()})
}
}

// Phase 2: run the prompt turn under a wall-clock timeout.
promptCtx, promptCancel := context.WithTimeout(context.Background(), time.Duration(*timeoutSec)*time.Second)
defer promptCancel()

presp, perr := conn.Prompt(promptCtx, acp.PromptRequest{
SessionId: sid,
Prompt: []acp.ContentBlock{acp.TextBlock(*promptStr)},
})
elapsed := time.Since(start)

// Attach summary counters gathered from the stream.
rec.mu.Lock()
result["tool_calls"] = rec.toolCalls
result["tool_updates"] = rec.toolUpdates
result["tool_names"] = rec.toolNames
result["tool_kind"] = rec.toolKind
result["tool_titles"] = rec.toolTitles
result["tool_status_end"] = rec.toolStatusEnd
result["thought_chunks"] = rec.thoughtChunks
result["agent_chunks"] = rec.agentChunks
result["agent_text_len"] = rec.agentTextLen
result["permission_reqs"] = rec.permissionN
result["plans"] = rec.plans
result["final_text"] = string(rec.finalText)
if rec.lastUsage != nil {
result["usage_update"] = json.RawMessage(rec.lastUsage)
}
rec.mu.Unlock()

result["elapsed_ms"] = elapsed.Milliseconds()

switch {
case perr != nil && promptCtx.Err() == context.DeadlineExceeded:
result["stop_reason"] = "TIMEOUT"
result["error"] = fmt.Sprintf("prompt turn exceeded %ds wall-clock", *timeoutSec)
// best-effort graceful cancel before killing
_ = conn.Cancel(context.Background(), acp.CancelNotification{SessionId: sid})
case perr != nil:
result["stop_reason"] = "PROMPT_ERROR"
result["error"] = perr.Error()
default:
result["stop_reason"] = string(presp.StopReason)
if presp.Usage != nil {
result["prompt_usage"] = presp.Usage
}
}

rec.line("result", result)

// Tear down the subprocess.
subCancel()
_ = cmd.Wait()

out, _ := json.Marshal(result)
fmt.Println(string(out))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

No signal handling — external SIGTERM (from orchestrate.py's outer timeout wrapper) can orphan the jcode acp subprocess.

orchestrate.py wraps this harness with the timeout coreutil as a backstop (see orchestrate.py line 191-192). timeout signals only its direct child (this harness), not further descendants. If this process is killed by that outer SIGTERM before reaching its own subCancel()/cmd.Wait() cleanup (e.g., because the earlier unbounded conn.Cancel is what caused the outer timeout to fire), the jcode acp grandchild subprocess is never signaled and can keep running indefinitely — exactly the "agent can hang" failure mode (F3) this harness is meant to detect and bound. Consider adding a signal.Notify handler for SIGTERM/SIGINT that cancels subCtx (killing the child) and flushes a terminal result before exiting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/harness/main.go` around lines 201 - 352, The main harness flow in
main() lacks signal handling, so an external SIGTERM/SIGINT can terminate the
harness before subCancel() and cmd.Wait() run, leaving the jcode acp subprocess
orphaned. Add a signal.Notify-based handler in main() that listens for
termination signals, cancels the subprocess context (subCtx via subCancel), and
records a terminal HARNESS_ERROR/TIMEOUT-style result before exiting. Make sure
the cleanup path still reaches the exec.CommandContext, conn.Cancel, and result
finalization logic even when interrupted.

Comment on lines +297 to +333
// Phase 2: run the prompt turn under a wall-clock timeout.
promptCtx, promptCancel := context.WithTimeout(context.Background(), time.Duration(*timeoutSec)*time.Second)
defer promptCancel()

presp, perr := conn.Prompt(promptCtx, acp.PromptRequest{
SessionId: sid,
Prompt: []acp.ContentBlock{acp.TextBlock(*promptStr)},
})
elapsed := time.Since(start)

// Attach summary counters gathered from the stream.
rec.mu.Lock()
result["tool_calls"] = rec.toolCalls
result["tool_updates"] = rec.toolUpdates
result["tool_names"] = rec.toolNames
result["tool_kind"] = rec.toolKind
result["tool_titles"] = rec.toolTitles
result["tool_status_end"] = rec.toolStatusEnd
result["thought_chunks"] = rec.thoughtChunks
result["agent_chunks"] = rec.agentChunks
result["agent_text_len"] = rec.agentTextLen
result["permission_reqs"] = rec.permissionN
result["plans"] = rec.plans
result["final_text"] = string(rec.finalText)
if rec.lastUsage != nil {
result["usage_update"] = json.RawMessage(rec.lastUsage)
}
rec.mu.Unlock()

result["elapsed_ms"] = elapsed.Milliseconds()

switch {
case perr != nil && promptCtx.Err() == context.DeadlineExceeded:
result["stop_reason"] = "TIMEOUT"
result["error"] = fmt.Sprintf("prompt turn exceeded %ds wall-clock", *timeoutSec)
// best-effort graceful cancel before killing
_ = conn.Cancel(context.Background(), acp.CancelNotification{SessionId: sid})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Unbounded conn.Cancel on timeout can hang the very timeout it's implementing.

When the prompt turn times out, the "best-effort graceful cancel" uses context.Background() with no deadline. If the agent/subprocess is genuinely unresponsive (the scenario this timeout exists to catch, cf. README's finding F3 about hangs), this call can block indefinitely, delaying subCancel()/cmd.Wait() that would actually terminate the subprocess.

🐛 Proposed fix: bound the cancel call
 	case perr != nil && promptCtx.Err() == context.DeadlineExceeded:
 		result["stop_reason"] = "TIMEOUT"
 		result["error"] = fmt.Sprintf("prompt turn exceeded %ds wall-clock", *timeoutSec)
 		// best-effort graceful cancel before killing
-		_ = conn.Cancel(context.Background(), acp.CancelNotification{SessionId: sid})
+		cancelCtx, cancelCtxCancel := context.WithTimeout(context.Background(), 5*time.Second)
+		_ = conn.Cancel(cancelCtx, acp.CancelNotification{SessionId: sid})
+		cancelCtxCancel()
📝 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.

Suggested change
// Phase 2: run the prompt turn under a wall-clock timeout.
promptCtx, promptCancel := context.WithTimeout(context.Background(), time.Duration(*timeoutSec)*time.Second)
defer promptCancel()
presp, perr := conn.Prompt(promptCtx, acp.PromptRequest{
SessionId: sid,
Prompt: []acp.ContentBlock{acp.TextBlock(*promptStr)},
})
elapsed := time.Since(start)
// Attach summary counters gathered from the stream.
rec.mu.Lock()
result["tool_calls"] = rec.toolCalls
result["tool_updates"] = rec.toolUpdates
result["tool_names"] = rec.toolNames
result["tool_kind"] = rec.toolKind
result["tool_titles"] = rec.toolTitles
result["tool_status_end"] = rec.toolStatusEnd
result["thought_chunks"] = rec.thoughtChunks
result["agent_chunks"] = rec.agentChunks
result["agent_text_len"] = rec.agentTextLen
result["permission_reqs"] = rec.permissionN
result["plans"] = rec.plans
result["final_text"] = string(rec.finalText)
if rec.lastUsage != nil {
result["usage_update"] = json.RawMessage(rec.lastUsage)
}
rec.mu.Unlock()
result["elapsed_ms"] = elapsed.Milliseconds()
switch {
case perr != nil && promptCtx.Err() == context.DeadlineExceeded:
result["stop_reason"] = "TIMEOUT"
result["error"] = fmt.Sprintf("prompt turn exceeded %ds wall-clock", *timeoutSec)
// best-effort graceful cancel before killing
_ = conn.Cancel(context.Background(), acp.CancelNotification{SessionId: sid})
// Phase 2: run the prompt turn under a wall-clock timeout.
promptCtx, promptCancel := context.WithTimeout(context.Background(), time.Duration(*timeoutSec)*time.Second)
defer promptCancel()
presp, perr := conn.Prompt(promptCtx, acp.PromptRequest{
SessionId: sid,
Prompt: []acp.ContentBlock{acp.TextBlock(*promptStr)},
})
elapsed := time.Since(start)
// Attach summary counters gathered from the stream.
rec.mu.Lock()
result["tool_calls"] = rec.toolCalls
result["tool_updates"] = rec.toolUpdates
result["tool_names"] = rec.toolNames
result["tool_kind"] = rec.toolKind
result["tool_titles"] = rec.toolTitles
result["tool_status_end"] = rec.toolStatusEnd
result["thought_chunks"] = rec.thoughtChunks
result["agent_chunks"] = rec.agentChunks
result["agent_text_len"] = rec.agentTextLen
result["permission_reqs"] = rec.permissionN
result["plans"] = rec.plans
result["final_text"] = string(rec.finalText)
if rec.lastUsage != nil {
result["usage_update"] = json.RawMessage(rec.lastUsage)
}
rec.mu.Unlock()
result["elapsed_ms"] = elapsed.Milliseconds()
switch {
case perr != nil && promptCtx.Err() == context.DeadlineExceeded:
result["stop_reason"] = "TIMEOUT"
result["error"] = fmt.Sprintf("prompt turn exceeded %ds wall-clock", *timeoutSec)
// best-effort graceful cancel before killing
cancelCtx, cancelCtxCancel := context.WithTimeout(context.Background(), 5*time.Second)
_ = conn.Cancel(cancelCtx, acp.CancelNotification{SessionId: sid})
cancelCtxCancel()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/harness/main.go` around lines 297 - 333, The timeout handling in
the Prompt flow can still hang because the best-effort `conn.Cancel` call uses
an unbounded `context.Background()`. Update the timeout branch in `main.go` so
the graceful cancel uses a short bounded context (or reuses the existing
`promptCtx` budget) before the later `subCancel()`/`cmd.Wait()` cleanup, and
keep the change localized around the `conn.Prompt`/`conn.Cancel` timeout path.

Comment thread agent-eval/README.md
Comment on lines +70 to +77
# 3. analyze + render the report
python3 agent-eval/analysis/analyze.py --runs-dir agent-eval/runs --out agent-eval/runs/analysis.json
python3 agent-eval/analysis/report.py \
--analysis agent-eval/runs/analysis.json \
--roundtable agent-eval/roundtable/roundtable.json \
--findings agent-eval/analysis/findings.json \
--runs-dir agent-eval/runs --out agent-eval/report/report.html
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Reproduction command writes analysis.json to the wrong (git-ignored) location.

analyze.py --out agent-eval/runs/analysis.json writes into runs/, which this same PR's .gitignore excludes. But the PR stack's checked-in generated artifact lives at agent-eval/report/analysis.json (per the "Generated analysis and report artifacts" layer). Following these exact instructions won't reproduce the committed report artifact path — worth aligning the doc (or the actual --out default) with where results are actually meant to land.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/README.md` around lines 70 - 77, The reproduction steps in README
use analyze.py and report.py with an output path that lands in the git-ignored
runs directory instead of the checked-in report artifact location. Update the
documented command, or align analyze.py’s --out default, so the generated
analysis.json matches the expected agent-eval/report/analysis.json path used by
the generated analysis/report artifacts and the report.py invocation.

@@ -0,0 +1 @@
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-default.css"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-head-nav.css" id="jtd-head-nav-stylesheet"> <style id="jtd-nav-activation"> .site-nav ul li a { background-image: none; } </style> <script src="/docs/assets/js/vendor/lunr.min.js"></script> <script src="/docs/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.8.0 --> <title>jcode | Think it. Code it.</title> <meta name="generator" content="Jekyll v4.4.1" /> <meta property="og:title" content="jcode" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <meta property="og:description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <link rel="canonical" href="/docs/assets/css/just-the-docs-head-nav.css" /> <meta property="og:url" content="/docs/assets/css/just-the-docs-head-nav.css" /> <meta property="og:site_name" content="jcode" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="jcode" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","description":"jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal.","headline":"jcode","url":"/docs/assets/css/just-the-docs-head-nav.css"}</script> <!-- End Jekyll SEO tag --> </head> <body> <a class="skip-to-main" href="#main-content">Skip to main content</a> <svg xmlns="http://www.w3.org/2000/svg" class="d-none"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <!-- Feather. MIT License: https://github.com/feathericons/feather/blob/master/LICENSE --> <symbol id="svg-external-link" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"> <title id="svg-external-link-title">(external link)</title> <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <!-- Bootstrap Icons. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md --> <symbol id="svg-copy" viewBox="0 0 16 16"> <title>Copy</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16"> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/> </svg> </symbol> <symbol id="svg-copied" viewBox="0 0 16 16"> <title>Copied</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16"> <path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/> </svg> </symbol> </svg> <header class="side-bar"> <div class="site-header"> <a href="/docs/" class="site-title lh-tight"> jcode </a> <button id="menu-button" class="site-button btn-reset" aria-label="Menu" aria-expanded="false"> <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg> </button> </div> <nav aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/docs/get-started.html" class="nav-list-link">Get Started</a></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Overview submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/overview.html" class="nav-list-link">Overview</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/overview/models.html" class="nav-list-link">Model Providers & Models</a></li><li class="nav-list-item"><a href="/docs/overview/agent.html" class="nav-list-link">Agent</a></li><li class="nav-list-item"><a href="/docs/overview/subagents.html" class="nav-list-link">Subagents</a></li><li class="nav-list-item"><a href="/docs/overview/agent-teams.html" class="nav-list-link">Agent Teams</a></li><li class="nav-list-item"><a href="/docs/overview/skills.html" class="nav-list-link">Skills</a></li><li class="nav-list-item"><a href="/docs/overview/plan-mode.html" class="nav-list-link">Plan Mode</a></li><li class="nav-list-item"><a href="/docs/overview/ssh.html" class="nav-list-link">SSH & Remote Work</a></li><li class="nav-list-item"><a href="/docs/overview/sessions.html" class="nav-list-link">Sessions & Resume</a></li><li class="nav-list-item"><a href="/docs/overview/context-memory.html" class="nav-list-link">Context & Memory</a></li><li class="nav-list-item"><a href="/docs/overview/mcp.html" class="nav-list-link">MCP Integration</a></li></ul></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Tools submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/tools.html" class="nav-list-link">Tools</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/tools/file-tools.html" class="nav-list-link">File Tools</a></li><li class="nav-list-item"><a href="/docs/tools/search-tools.html" class="nav-list-link">Search Tools</a></li><li class="nav-list-item"><a href="/docs/tools/execute.html" class="nav-list-link">Execute</a></li><li class="nav-list-item"><a href="/docs/tools/task-management.html" class="nav-list-link">Task Management</a></li></ul></li><li class="nav-list-item"><a href="/docs/web-interface.html" class="nav-list-link">Web Interface</a></li><li class="nav-list-item"><a href="/docs/configuration.html" class="nav-list-link">Configuration</a></li><li class="nav-list-item"><a href="/docs/commands.html" class="nav-list-link">Commands & Shortcuts</a></li></ul> </nav> <div class="d-md-block d-none site-footer"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </header> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search" role="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search jcode" autocomplete="off"> <label for="search-input" class="search-label"> <span class="sr-only">Search jcode</span> <svg viewBox="0 0 24 24" class="search-icon" aria-hidden="true"><use xlink:href="#svg-search"></use></svg> </label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div class="main-content-wrap"> <div id="main-content" class="main-content"> <main> <h.site-nav ul li a { background-image: linear-gradient(-90deg, rgb(234.8, 236.82, 244.9) 0%, rgba(234.8, 236.82, 244.9, 0.8) 80%, rgba(234.8, 236.82, 244.9, 0) 100%); } </main> <hr> <footer> <p><a href="#top" id="back-to-top">Back to top</a></p> <div class="d-md-none mt-4 fs-2"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </footer> </div> </div> <div class="search-overlay"></div> </div> </body> </html>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Confirm every page's head-nav CSS file is similarly corrupted or if this is isolated.
fd -e css . agent-eval/site/docs/assets/css --exec sh -c 'echo "=== {} ==="; head -c 200 "{}"'

Repository: cnjack/jcode

Length of output: 1210


agent-eval/site/docs/assets/css/just-the-docs-head-nav.css is not CSS

This asset contains a full HTML document, so the nav-highlighting stylesheet can’t be parsed or applied. The other files in agent-eval/site/docs/assets/css are normal CSS, so this looks isolated to the generator/build step that wrote the wrong artifact here.

🧰 Tools
🪛 Stylelint (17.14.0)

[error] 1-1: Missed semicolon (CssSyntaxError)

(CssSyntaxError)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/site/docs/assets/css/just-the-docs-head-nav.css` at line 1, The
just-the-docs-head-nav stylesheet asset is being generated as a full HTML
document instead of CSS, so fix the build/export step that writes this file and
ensure it emits only valid stylesheet rules. Use the asset target referenced by
just-the-docs-head-nav.css and verify the output matches the other CSS assets in
the same directory, with no HTML head/body markup or embedded page content.

Source: Linters/SAST tools

@@ -0,0 +1,89 @@
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-default.css"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-head-nav.css" id="jtd-head-nav-stylesheet"> <style id="jtd-nav-activation"> .site-nav > ul.nav-list:first-child > li:not(:nth-child(5)) > a, .site-nav > ul.nav-list:first-child > li > ul > li a { background-image: none; } .site-nav > ul.nav-list:not(:first-child) a, .site-nav li.external a { background-image: none; } .site-nav > ul.nav-list:first-child > li:nth-child(5) > a { font-weight: 600; text-decoration: none; }.site-nav > ul.nav-list:first-child > li:nth-child(5) > button svg { transform: rotate(-90deg); }.site-nav > ul.nav-list:first-child > li.nav-list-item:nth-child(5) > ul.nav-list { display: block; } </style> <script src="/docs/assets/js/vendor/lunr.min.js"></script> <script src="/docs/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.8.0 --> <title>Configuration | jcode</title> <meta name="generator" content="Jekyll v4.4.1" /> <meta property="og:title" content="Configuration" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <meta property="og:description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <link rel="canonical" href="/docs/configuration.html" /> <meta property="og:url" content="/docs/configuration.html" /> <meta property="og:site_name" content="jcode" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Configuration" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","description":"jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal.","headline":"Configuration","url":"/docs/configuration.html"}</script> <!-- End Jekyll SEO tag --> </head> <body> <a class="skip-to-main" href="#main-content">Skip to main content</a> <svg xmlns="http://www.w3.org/2000/svg" class="d-none"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <!-- Feather. MIT License: https://github.com/feathericons/feather/blob/master/LICENSE --> <symbol id="svg-external-link" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"> <title id="svg-external-link-title">(external link)</title> <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <!-- Bootstrap Icons. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md --> <symbol id="svg-copy" viewBox="0 0 16 16"> <title>Copy</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16"> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/> </svg> </symbol> <symbol id="svg-copied" viewBox="0 0 16 16"> <title>Copied</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16"> <path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/> </svg> </symbol> </svg> <header class="side-bar"> <div class="site-header"> <a href="/docs/" class="site-title lh-tight"> jcode </a> <button id="menu-button" class="site-button btn-reset" aria-label="Menu" aria-expanded="false"> <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg> </button> </div> <nav aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/docs/get-started.html" class="nav-list-link">Get Started</a></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Overview submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/overview.html" class="nav-list-link">Overview</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/overview/models.html" class="nav-list-link">Model Providers & Models</a></li><li class="nav-list-item"><a href="/docs/overview/agent.html" class="nav-list-link">Agent</a></li><li class="nav-list-item"><a href="/docs/overview/subagents.html" class="nav-list-link">Subagents</a></li><li class="nav-list-item"><a href="/docs/overview/agent-teams.html" class="nav-list-link">Agent Teams</a></li><li class="nav-list-item"><a href="/docs/overview/skills.html" class="nav-list-link">Skills</a></li><li class="nav-list-item"><a href="/docs/overview/plan-mode.html" class="nav-list-link">Plan Mode</a></li><li class="nav-list-item"><a href="/docs/overview/ssh.html" class="nav-list-link">SSH & Remote Work</a></li><li class="nav-list-item"><a href="/docs/overview/sessions.html" class="nav-list-link">Sessions & Resume</a></li><li class="nav-list-item"><a href="/docs/overview/context-memory.html" class="nav-list-link">Context & Memory</a></li><li class="nav-list-item"><a href="/docs/overview/mcp.html" class="nav-list-link">MCP Integration</a></li></ul></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Tools submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/tools.html" class="nav-list-link">Tools</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/tools/file-tools.html" class="nav-list-link">File Tools</a></li><li class="nav-list-item"><a href="/docs/tools/search-tools.html" class="nav-list-link">Search Tools</a></li><li class="nav-list-item"><a href="/docs/tools/execute.html" class="nav-list-link">Execute</a></li><li class="nav-list-item"><a href="/docs/tools/task-management.html" class="nav-list-link">Task Management</a></li></ul></li><li class="nav-list-item"><a href="/docs/web-interface.html" class="nav-list-link">Web Interface</a></li><li class="nav-list-item"><a href="/docs/configuration.html" class="nav-list-link">Configuration</a></li><li class="nav-list-item"><a href="/docs/commands.html" class="nav-list-link">Commands & Shortcuts</a></li></ul> </nav> <div class="d-md-block d-none site-footer"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </header> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search" role="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search jcode" autocomplete="off"> <label for="search-input" class="search-label"> <span class="sr-only">Search jcode</span> <svg viewBox="0 0 24 24" class="search-icon" aria-hidden="true"><use xlink:href="#svg-search"></use></svg> </label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div class="main-content-wrap"> <div id="main-content" class="main-content"> <main> <h1 id="configuration"> <a href="#configuration" class="anchor-heading" aria-labelledby="configuration"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Configuration </h1> <p>jcode stores all configuration in a single JSON file at <code class="language-plaintext highlighter-rouge">~/.jcode/config.json</code>. The setup wizard creates this file on first launch.</p> <h2 id="config-file-location"> <a href="#config-file-location" class="anchor-heading" aria-labelledby="config-file-location"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Config File Location </h2> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/.jcode/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Broken relative link to MCP Integration page.

The mcp_servers section links with <a href="mcp">MCP Integration</a>. Relative to /docs/configuration.html, this resolves to /docs/mcp, but the actual page is at /docs/overview/mcp.html (per the nav links elsewhere in this same file). This link will 404.

🔗 Proposed fix
-<p>MCP server definitions. See <a href="mcp">MCP Integration</a>.</p>
+<p>MCP server definitions. See <a href="/docs/overview/mcp.html">MCP Integration</a>.</p>
📝 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.

Suggested change
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-default.css"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-head-nav.css" id="jtd-head-nav-stylesheet"> <style id="jtd-nav-activation"> .site-nav > ul.nav-list:first-child > li:not(:nth-child(5)) > a, .site-nav > ul.nav-list:first-child > li > ul > li a { background-image: none; } .site-nav > ul.nav-list:not(:first-child) a, .site-nav li.external a { background-image: none; } .site-nav > ul.nav-list:first-child > li:nth-child(5) > a { font-weight: 600; text-decoration: none; }.site-nav > ul.nav-list:first-child > li:nth-child(5) > button svg { transform: rotate(-90deg); }.site-nav > ul.nav-list:first-child > li.nav-list-item:nth-child(5) > ul.nav-list { display: block; } </style> <script src="/docs/assets/js/vendor/lunr.min.js"></script> <script src="/docs/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.8.0 --> <title>Configuration | jcode</title> <meta name="generator" content="Jekyll v4.4.1" /> <meta property="og:title" content="Configuration" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <meta property="og:description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <link rel="canonical" href="/docs/configuration.html" /> <meta property="og:url" content="/docs/configuration.html" /> <meta property="og:site_name" content="jcode" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Configuration" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","description":"jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal.","headline":"Configuration","url":"/docs/configuration.html"}</script> <!-- End Jekyll SEO tag --> </head> <body> <a class="skip-to-main" href="#main-content">Skip to main content</a> <svg xmlns="http://www.w3.org/2000/svg" class="d-none"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <!-- Feather. MIT License: https://github.com/feathericons/feather/blob/master/LICENSE --> <symbol id="svg-external-link" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"> <title id="svg-external-link-title">(external link)</title> <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <!-- Bootstrap Icons. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md --> <symbol id="svg-copy" viewBox="0 0 16 16"> <title>Copy</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16"> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/> </svg> </symbol> <symbol id="svg-copied" viewBox="0 0 16 16"> <title>Copied</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16"> <path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/> </svg> </symbol> </svg> <header class="side-bar"> <div class="site-header"> <a href="/docs/" class="site-title lh-tight"> jcode </a> <button id="menu-button" class="site-button btn-reset" aria-label="Menu" aria-expanded="false"> <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg> </button> </div> <nav aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/docs/get-started.html" class="nav-list-link">Get Started</a></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Overview submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/overview.html" class="nav-list-link">Overview</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/overview/models.html" class="nav-list-link">Model Providers & Models</a></li><li class="nav-list-item"><a href="/docs/overview/agent.html" class="nav-list-link">Agent</a></li><li class="nav-list-item"><a href="/docs/overview/subagents.html" class="nav-list-link">Subagents</a></li><li class="nav-list-item"><a href="/docs/overview/agent-teams.html" class="nav-list-link">Agent Teams</a></li><li class="nav-list-item"><a href="/docs/overview/skills.html" class="nav-list-link">Skills</a></li><li class="nav-list-item"><a href="/docs/overview/plan-mode.html" class="nav-list-link">Plan Mode</a></li><li class="nav-list-item"><a href="/docs/overview/ssh.html" class="nav-list-link">SSH & Remote Work</a></li><li class="nav-list-item"><a href="/docs/overview/sessions.html" class="nav-list-link">Sessions & Resume</a></li><li class="nav-list-item"><a href="/docs/overview/context-memory.html" class="nav-list-link">Context & Memory</a></li><li class="nav-list-item"><a href="/docs/overview/mcp.html" class="nav-list-link">MCP Integration</a></li></ul></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Tools submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/tools.html" class="nav-list-link">Tools</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/tools/file-tools.html" class="nav-list-link">File Tools</a></li><li class="nav-list-item"><a href="/docs/tools/search-tools.html" class="nav-list-link">Search Tools</a></li><li class="nav-list-item"><a href="/docs/tools/execute.html" class="nav-list-link">Execute</a></li><li class="nav-list-item"><a href="/docs/tools/task-management.html" class="nav-list-link">Task Management</a></li></ul></li><li class="nav-list-item"><a href="/docs/web-interface.html" class="nav-list-link">Web Interface</a></li><li class="nav-list-item"><a href="/docs/configuration.html" class="nav-list-link">Configuration</a></li><li class="nav-list-item"><a href="/docs/commands.html" class="nav-list-link">Commands & Shortcuts</a></li></ul> </nav> <div class="d-md-block d-none site-footer"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </header> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search" role="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search jcode" autocomplete="off"> <label for="search-input" class="search-label"> <span class="sr-only">Search jcode</span> <svg viewBox="0 0 24 24" class="search-icon" aria-hidden="true"><use xlink:href="#svg-search"></use></svg> </label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div class="main-content-wrap"> <div id="main-content" class="main-content"> <main> <h1 id="configuration"> <a href="#configuration" class="anchor-heading" aria-labelledby="configuration"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Configuration </h1> <p>jcode stores all configuration in a single JSON file at <code class="language-plaintext highlighter-rouge">~/.jcode/config.json</code>. The setup wizard creates this file on first launch.</p> <h2 id="config-file-location"> <a href="#config-file-location" class="anchor-heading" aria-labelledby="config-file-location"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Config File Location </h2> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/.jcode/
<p>MCP server definitions. See <a href="/docs/overview/mcp.html">MCP Integration</a>.</p>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/site/docs/configuration.html` at line 1, The Configuration page
has a broken relative link for MCP Integration in the `mcp_servers` section.
Update the anchor in the configuration docs to point to the actual MCP page path
used elsewhere in the file, matching the `Overview`/`MCP Integration` nav
target. Use the surrounding `mcp_servers` documentation block and the `MCP
Integration` link text to locate and replace the incorrect href so it resolves
correctly from `configuration.html`.

@@ -0,0 +1,19 @@
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-default.css"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-head-nav.css" id="jtd-head-nav-stylesheet"> <style id="jtd-nav-activation"> .site-nav > ul.nav-list:first-child > li:not(:nth-child(1)) > a, .site-nav > ul.nav-list:first-child > li > ul > li a { background-image: none; } .site-nav > ul.nav-list:not(:first-child) a, .site-nav li.external a { background-image: none; } .site-nav > ul.nav-list:first-child > li:nth-child(1) > a { font-weight: 600; text-decoration: none; }.site-nav > ul.nav-list:first-child > li:nth-child(1) > button svg { transform: rotate(-90deg); }.site-nav > ul.nav-list:first-child > li.nav-list-item:nth-child(1) > ul.nav-list { display: block; } </style> <script src="/docs/assets/js/vendor/lunr.min.js"></script> <script src="/docs/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.8.0 --> <title>Get Started | jcode</title> <meta name="generator" content="Jekyll v4.4.1" /> <meta property="og:title" content="Get Started" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <meta property="og:description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <link rel="canonical" href="/docs/get-started.html" /> <meta property="og:url" content="/docs/get-started.html" /> <meta property="og:site_name" content="jcode" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Get Started" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","description":"jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal.","headline":"Get Started","url":"/docs/get-started.html"}</script> <!-- End Jekyll SEO tag --> </head> <body> <a class="skip-to-main" href="#main-content">Skip to main content</a> <svg xmlns="http://www.w3.org/2000/svg" class="d-none"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <!-- Feather. MIT License: https://github.com/feathericons/feather/blob/master/LICENSE --> <symbol id="svg-external-link" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"> <title id="svg-external-link-title">(external link)</title> <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <!-- Bootstrap Icons. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md --> <symbol id="svg-copy" viewBox="0 0 16 16"> <title>Copy</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16"> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/> </svg> </symbol> <symbol id="svg-copied" viewBox="0 0 16 16"> <title>Copied</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16"> <path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/> </svg> </symbol> </svg> <header class="side-bar"> <div class="site-header"> <a href="/docs/" class="site-title lh-tight"> jcode </a> <button id="menu-button" class="site-button btn-reset" aria-label="Menu" aria-expanded="false"> <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg> </button> </div> <nav aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/docs/get-started.html" class="nav-list-link">Get Started</a></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Overview submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/overview.html" class="nav-list-link">Overview</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/overview/models.html" class="nav-list-link">Model Providers & Models</a></li><li class="nav-list-item"><a href="/docs/overview/agent.html" class="nav-list-link">Agent</a></li><li class="nav-list-item"><a href="/docs/overview/subagents.html" class="nav-list-link">Subagents</a></li><li class="nav-list-item"><a href="/docs/overview/agent-teams.html" class="nav-list-link">Agent Teams</a></li><li class="nav-list-item"><a href="/docs/overview/skills.html" class="nav-list-link">Skills</a></li><li class="nav-list-item"><a href="/docs/overview/plan-mode.html" class="nav-list-link">Plan Mode</a></li><li class="nav-list-item"><a href="/docs/overview/ssh.html" class="nav-list-link">SSH & Remote Work</a></li><li class="nav-list-item"><a href="/docs/overview/sessions.html" class="nav-list-link">Sessions & Resume</a></li><li class="nav-list-item"><a href="/docs/overview/context-memory.html" class="nav-list-link">Context & Memory</a></li><li class="nav-list-item"><a href="/docs/overview/mcp.html" class="nav-list-link">MCP Integration</a></li></ul></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Tools submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/tools.html" class="nav-list-link">Tools</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/tools/file-tools.html" class="nav-list-link">File Tools</a></li><li class="nav-list-item"><a href="/docs/tools/search-tools.html" class="nav-list-link">Search Tools</a></li><li class="nav-list-item"><a href="/docs/tools/execute.html" class="nav-list-link">Execute</a></li><li class="nav-list-item"><a href="/docs/tools/task-management.html" class="nav-list-link">Task Management</a></li></ul></li><li class="nav-list-item"><a href="/docs/web-interface.html" class="nav-list-link">Web Interface</a></li><li class="nav-list-item"><a href="/docs/configuration.html" class="nav-list-link">Configuration</a></li><li class="nav-list-item"><a href="/docs/commands.html" class="nav-list-link">Commands & Shortcuts</a></li></ul> </nav> <div class="d-md-block d-none site-footer"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </header> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search" role="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search jcode" autocomplete="off"> <label for="search-input" class="search-label"> <span class="sr-only">Search jcode</span> <svg viewBox="0 0 24 24" class="search-icon" aria-hidden="true"><use xlink:href="#svg-search"></use></svg> </label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div class="main-content-wrap"> <div id="main-content" class="main-content"> <main> <h1 id="get-started"> <a href="#get-started" class="anchor-heading" aria-labelledby="get-started"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Get Started </h1> <h2 id="prerequisites"> <a href="#prerequisites" class="anchor-heading" aria-labelledby="prerequisites"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Prerequisites </h2> <ul> <li><strong>Go 1.22+</strong> installed</li> <li>An <strong>API key</strong> from an OpenAI-compatible provider (OpenAI, Anthropic, Azure, etc.)</li> </ul> <h2 id="install"> <a href="#install" class="anchor-heading" aria-labelledby="install"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Install </h2> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">install </span>github.com/cnjack/docs/cmd/jcode@latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Incorrect Go module path in install instructions.

go install github.com/cnjack/docs/cmd/jcode@latest references the cnjack/docs repository, but the actual repository (per the git clone instruction later in the same file and the PR URL) is cnjack/jcode. This will fail for anyone following the docs.

🔗 Proposed fix
-go install github.com/cnjack/docs/cmd/jcode@latest
+go install github.com/cnjack/jcode/cmd/jcode@latest
📝 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.

Suggested change
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-default.css"> <link rel="stylesheet" href="/docs/assets/css/just-the-docs-head-nav.css" id="jtd-head-nav-stylesheet"> <style id="jtd-nav-activation"> .site-nav > ul.nav-list:first-child > li:not(:nth-child(1)) > a, .site-nav > ul.nav-list:first-child > li > ul > li a { background-image: none; } .site-nav > ul.nav-list:not(:first-child) a, .site-nav li.external a { background-image: none; } .site-nav > ul.nav-list:first-child > li:nth-child(1) > a { font-weight: 600; text-decoration: none; }.site-nav > ul.nav-list:first-child > li:nth-child(1) > button svg { transform: rotate(-90deg); }.site-nav > ul.nav-list:first-child > li.nav-list-item:nth-child(1) > ul.nav-list { display: block; } </style> <script src="/docs/assets/js/vendor/lunr.min.js"></script> <script src="/docs/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.8.0 --> <title>Get Started | jcode</title> <meta name="generator" content="Jekyll v4.4.1" /> <meta property="og:title" content="Get Started" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <meta property="og:description" content="jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal." /> <link rel="canonical" href="/docs/get-started.html" /> <meta property="og:url" content="/docs/get-started.html" /> <meta property="og:site_name" content="jcode" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Get Started" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","description":"jcode — Your AI Coding Companion. An intelligent coding agent that lives in your terminal.","headline":"Get Started","url":"/docs/get-started.html"}</script> <!-- End Jekyll SEO tag --> </head> <body> <a class="skip-to-main" href="#main-content">Skip to main content</a> <svg xmlns="http://www.w3.org/2000/svg" class="d-none"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <!-- Feather. MIT License: https://github.com/feathericons/feather/blob/master/LICENSE --> <symbol id="svg-external-link" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"> <title id="svg-external-link-title">(external link)</title> <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <!-- Bootstrap Icons. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md --> <symbol id="svg-copy" viewBox="0 0 16 16"> <title>Copy</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16"> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/> </svg> </symbol> <symbol id="svg-copied" viewBox="0 0 16 16"> <title>Copied</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16"> <path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/> </svg> </symbol> </svg> <header class="side-bar"> <div class="site-header"> <a href="/docs/" class="site-title lh-tight"> jcode </a> <button id="menu-button" class="site-button btn-reset" aria-label="Menu" aria-expanded="false"> <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg> </button> </div> <nav aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/docs/get-started.html" class="nav-list-link">Get Started</a></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Overview submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/overview.html" class="nav-list-link">Overview</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/overview/models.html" class="nav-list-link">Model Providers & Models</a></li><li class="nav-list-item"><a href="/docs/overview/agent.html" class="nav-list-link">Agent</a></li><li class="nav-list-item"><a href="/docs/overview/subagents.html" class="nav-list-link">Subagents</a></li><li class="nav-list-item"><a href="/docs/overview/agent-teams.html" class="nav-list-link">Agent Teams</a></li><li class="nav-list-item"><a href="/docs/overview/skills.html" class="nav-list-link">Skills</a></li><li class="nav-list-item"><a href="/docs/overview/plan-mode.html" class="nav-list-link">Plan Mode</a></li><li class="nav-list-item"><a href="/docs/overview/ssh.html" class="nav-list-link">SSH & Remote Work</a></li><li class="nav-list-item"><a href="/docs/overview/sessions.html" class="nav-list-link">Sessions & Resume</a></li><li class="nav-list-item"><a href="/docs/overview/context-memory.html" class="nav-list-link">Context & Memory</a></li><li class="nav-list-item"><a href="/docs/overview/mcp.html" class="nav-list-link">MCP Integration</a></li></ul></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Tools submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/docs/tools.html" class="nav-list-link">Tools</a><ul class="nav-list"><li class="nav-list-item"><a href="/docs/tools/file-tools.html" class="nav-list-link">File Tools</a></li><li class="nav-list-item"><a href="/docs/tools/search-tools.html" class="nav-list-link">Search Tools</a></li><li class="nav-list-item"><a href="/docs/tools/execute.html" class="nav-list-link">Execute</a></li><li class="nav-list-item"><a href="/docs/tools/task-management.html" class="nav-list-link">Task Management</a></li></ul></li><li class="nav-list-item"><a href="/docs/web-interface.html" class="nav-list-link">Web Interface</a></li><li class="nav-list-item"><a href="/docs/configuration.html" class="nav-list-link">Configuration</a></li><li class="nav-list-item"><a href="/docs/commands.html" class="nav-list-link">Commands & Shortcuts</a></li></ul> </nav> <div class="d-md-block d-none site-footer"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </header> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search" role="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search jcode" autocomplete="off"> <label for="search-input" class="search-label"> <span class="sr-only">Search jcode</span> <svg viewBox="0 0 24 24" class="search-icon" aria-hidden="true"><use xlink:href="#svg-search"></use></svg> </label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div class="main-content-wrap"> <div id="main-content" class="main-content"> <main> <h1 id="get-started"> <a href="#get-started" class="anchor-heading" aria-labelledby="get-started"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Get Started </h1> <h2 id="prerequisites"> <a href="#prerequisites" class="anchor-heading" aria-labelledby="prerequisites"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Prerequisites </h2> <ul> <li><strong>Go 1.22+</strong> installed</li> <li>An <strong>API key</strong> from an OpenAI-compatible provider (OpenAI, Anthropic, Azure, etc.)</li> </ul> <h2 id="install"> <a href="#install" class="anchor-heading" aria-labelledby="install"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Install </h2> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go <span class="nb">install </span>github.com/cnjack/docs/cmd/jcode@latest
go <span class="nb">install </span>github.com/cnjack/jcode/cmd/jcode@latest
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/site/docs/get-started.html` at line 1, The install command in the
Get Started docs uses the wrong Go module path, pointing to cnjack/docs instead
of the actual jcode repository. Update the install instruction in the Get
Started page to use the same repository path as the later git clone guidance, so
the command resolves the correct module for jcode.

<a href="docs/">Documentation</a> ·
<a href="index.html">Home</a>
</p>
<p style="margin-top:10px;font-size:.85rem;color:var(--muted);">津ICP备13004281号-4</p>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stray/unrelated ICP registration footer text.

津ICP备13004281号-4 in the footer looks like leftover boilerplate unrelated to this repo (jcode/GitHub project), not an actual registration for this site. If this is placeholder/copied content, remove it before publishing to avoid misleading legal/compliance info.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/site/showcase.html` at line 61, The footer contains stray ICP
registration boilerplate that appears unrelated to this site. Remove the
hardcoded ICP text from the footer content in the showcase page markup so only
relevant project/footer information remains, and keep the affected footer
element consistent with the rest of the page structure.

Comment on lines +61 to +76
def build_home(home_dir: Path, model_id: str, max_iter: int):
(home_dir / ".jcode" / "cache").mkdir(parents=True, exist_ok=True)
cfg = json.loads(REAL_CFG.read_text())
provs = cfg.get("providers") or cfg.get("models") or {}
out = {
"providers": provs,
"model": model_id,
"auto_approve": True,
"default_mode": "full_access",
"max_iterations": max_iter,
}
(home_dir / ".jcode" / "config.json").write_text(json.dumps(out, indent=2))
if REAL_CACHE.exists():
shutil.copy(REAL_CACHE, home_dir / ".jcode" / "cache" / "models_dev.json")
if REAL_MODELSTATE.exists():
shutil.copy(REAL_MODELSTATE, home_dir / ".jcode" / "model_state.json")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Live provider API keys are copied into every per-run HOME and retained post-run.

build_home copies the real config's providers (i.e., live API keys per the README) into each throwaway HOME. _prune_home (Line 296) explicitly keeps config.json, so those live credentials persist on disk in every run directory produced by a sweep (potentially dozens per model×tier). While runs/ is git-ignored, this still multiplies the exposure surface of live secrets across many directories that could end up in backups, debug archives, or shared for troubleshooting. Since downstream consumers (analyze.py/report.py) only need usage, sessions, and debug.log, consider redacting the provider credentials from the persisted config.json (or dropping it) once a run completes.

🔒 Proposed fix: redact credentials before pruning
 def _prune_home(home_dir: Path):
     keep = {"usage", "sessions", "debug.log", "config.json"}
     jc = home_dir / ".jcode"
     if not jc.exists():
         return
+    cfg_path = jc / "config.json"
+    if cfg_path.exists():
+        try:
+            cfg = json.loads(cfg_path.read_text())
+            cfg["providers"] = "REDACTED"
+            cfg_path.write_text(json.dumps(cfg, indent=2))
+        except Exception:
+            pass
     for child in jc.iterdir():
         if child.name not in keep:
🧰 Tools
🪛 ast-grep (0.44.0)

[info] 71-71: use jsonify instead of json.dumps for JSON output
Context: json.dumps(out, indent=2)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent-eval/suite/orchestrate.py` around lines 61 - 76, The per-run HOME setup
is persisting live provider credentials in config.json via build_home, and
_prune_home is keeping that file after the run. Update build_home to redact or
omit the providers block when writing the run-local config, or add a post-run
cleanup step in _prune_home to strip secrets before preserving config.json. Keep
only the data needed by analyze.py and report.py (usage, sessions, debug.log),
and ensure the final persisted config no longer contains API keys.

@cnjack cnjack merged commit 0052a43 into main Jul 3, 2026
3 checks passed
@cnjack cnjack deleted the feat/agent-eval-showcase branch July 3, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant