Skip to content

Pr 4333#4856

Open
45Harry wants to merge 58 commits into
tinyhumansai:mainfrom
45Harry:pr-4333
Open

Pr 4333#4856
45Harry wants to merge 58 commits into
tinyhumansai:mainfrom
45Harry:pr-4333

Conversation

@45Harry

@45Harry 45Harry commented Jul 14, 2026

Copy link
Copy Markdown

Summary

  • What changed and why.
  • Keep this to 3-6 bullets focused on user-visible or architecture-impacting changes.

Problem

  • What issue or risk this PR addresses.
  • Include context needed for reviewers to evaluate correctness quickly.

Solution

  • How the implementation solves the problem.
  • Note important design decisions and tradeoffs.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/ci-lite.yml. Run pnpm test:coverage and pnpm test:rust locally; PRs below 80% on changed lines will not merge.
  • Coverage matrix updated — added/removed/renamed feature rows in docs/TEST-COVERAGE-MATRIX.md reflect this change (or N/A: behaviour-only change)
  • All affected feature IDs from the matrix are listed in the PR description under ## Related
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md)
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

  • Runtime/platform impact (desktop/mobile/web/CLI), if any.
  • Performance, security, migration, or compatibility implications.

Related

  • Closes:
  • Follow-up PR(s)/TODOs:

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key:
  • URL:

Commit & Branch

  • Branch:
  • Commit SHA:

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests:
  • Rust fmt/check (if changed):
  • Tauri fmt/check (if changed):

Validation Blocked

  • command:
  • error:
  • impact:

Behavior Changes

  • Intended behavior change:
  • User-visible effect:

Parity Contract

  • Legacy behavior preserved:
  • Guard/fallback/dispatch parity checks:

Duplicate / Superseded PR Handling

  • Duplicate PR(s):
  • Canonical PR:
  • Resolution (closed/superseded/updated):

Summary by CodeRabbit

  • New Features

    • Added a full-screen interactive chat experience with message scrolling, command search, model selection, and tool approval prompts.
    • Added chat commands for conversations, model switching, authentication, status, memory, files, configuration, usage, and available tools.
    • Added new assistant skills for planning, coding, debugging, testing, browser automation, deployment, design, memory, voice, and reviews.
    • Skills can now be discovered across supported project configuration locations.
  • Documentation

    • Expanded guidance for assistant skills, workflows, configuration, and local feature testing.
  • Chores

    • Added a Linux build workflow for producing downloadable application binaries.

Harry and others added 30 commits June 30, 2026 15:49
- New openhuman chat subcommand (interactive REPL)
- openhuman with no args starts chat (Claude Code-like)
- npm package README with install/usage docs
- Default dispatch to chat when no subcommand given
Default changed to start chat directly, update all docs.
- Type / or press Enter on empty line to open command menu
- /model <name> to switch AI model mid-session
- /login to authenticate with token
- /session to show auth status
- Better UI with styled prompts, thinking indicator, error display
- First-run friendly error messages with guidance
- /threads: list threads, select to view messages
- /memory: browse namespaces, list docs, semantic query, recall
- /config: show config snapshots (full, model, agent, paths)
- /files: browse memory files
- /status: auth status with user info & balance
- /logout: de-authenticate
- /model: switch AI model
- Subcommand routing: /memory list, /memory query, /config model, etc.
- / and Enter triggers command menu picker
- Commands organized as structured enum with completions
- npm README updated with full command reference
Swap dialoguer::Input for raw-mode read_line_raw using
console::Term::read_char() so typing / as first char shows
the command menu instantly, matching Claude Code UX.
Full terminal UI matching opencode-style interaction:
- OpenHuman ASCII logo and styling preserved
- Chat panel with scrollable message list
- Input bar with inline cursor editing
- Command popup: type / instantly shows filtered command list
- Tab toggles menu, Enter selects, Esc dismisses
- Ctrl+C / /exit to quit
- Agent integration via channels
- TUI sends messages to agent thread via mpsc channel
- Agent processes messages on tokio runtime, sends responses back
- No more placeholder echo responses
- Cleaned up old REPL code replaced by TUI
…mands

- /model shows model selection popup at top of TUI
- Arrow keys navigate, Enter selects, Esc cancels
- AgentCmd enum + command channel for backend actions (SwitchModel)
- All other commands show local system messages
- Proper separation: chat messages go to agent, commands stay local
- Expand CMDS to include login, logout, status, threads, memory, files,
  config, usage, tools (12 total)
- Add AgentCmd variants for all backend-routed commands
- Wire Enter handler: /model -> popup, /help -> local list,
  /exit -> quit, backend cmds -> AgentCmd channel, rest -> agent
- Add handle_cmd dispatcher in chat_cli.rs with per-command handler fns
- Handle SwitchModel (recreate agent), Login/Logout (session mgmt),
  Status (config + auth), Tools (agent.tools()), Config (format fields)
- Remove old /t command alias (superceded by /threads)
- Fix Config field access (action_dir is PathBuf, not Option)
- /threads: calls memory_conversations::list_threads(workspace_dir)
  to show actual thread titles and message counts
- /memory: calls memory_list_namespaces(EmptyRequest{}) for
  real namespace listing via memory store client
- /files: calls ai_list_memory_files to list stored memory files
- /usage: uses cost::try_global() + get_daily_history(7) to
  show daily token counts and costs
- /status: uses build_session_state for richer auth info
- /config: shows all Config fields (workspace, action dir, model,
  API/inference URLs, temperature, language, schema version)
- /tools: unchanged (uses agent.tools())
- /login: shows helpful message about CLI login or env var
- /usage now creates a CostTracker from config.cost + workspace_dir
  when the global tracker is uninitialized (was always None since
  cost::init_global is never called in the CLI path)
- Remove unused get_session_token, memory_list_documents,
  DailyCostEntry, ListDocumentsRequest imports
- PageUp/PageDown scroll through message history; ↑↓ scroll when
  input is empty (so you don't need Page keys on compact keyboards)
- Status bar at bottom shows model name + controls hint
- /new clears all chat messages and resets scroll
- New messages auto-scroll to bottom (reset scroll_offset = 0)
- Model name parsed from 'Switched to model: ...' response
Override action_dir to current working directory after loading config,
so the agent operates in the directory where the user launched openhuman
instead of the default ~/OpenHuman/projects.
Require initial model name from config so status bar shows the
actual model (e.g. chat-v1) immediately instead of 'unknown'.
# Conflicts:
#	Cargo.lock
senamakel and others added 22 commits July 8, 2026 21:10
# Conflicts:
#	app/src-tauri/Cargo.lock
# Conflicts:
#	src/openhuman/channels/providers/web/mod.rs
#	src/openhuman/memory/chat.rs
#	src/openhuman/memory/tree_source/file.rs
#	src/openhuman/sandbox/docker.rs
# Conflicts:
#	app/src-tauri/Cargo.lock
- Add 11 SKILL.md skill definitions (review, plan, memory, debug, code,
  workflow, search, voice, browser, agent, config) in both .claude/skills/
  and .openhuman/skills/ for cross-tool compatibility
- Configure MCP servers (git, filesystem, github, openhuman-docs)
- Set up permissions, approval gates, and voice/browser/settings config
- Add .claude/skills/ to openhuman skill discovery paths
- Create project trust marker for project-scope skill loading
- Fix duplicate import in dictation_listener.rs

All features verified working with local qwen3:0.6b via Ollama.
- 14 agent profiles: architectobot, build-agent, codecrusher, deploy-agent,
  designguru, dev-agent, memory-keeper, mobile-agent, pr-manager,
  pr-manager-lite, pr-reviewer, qualityqueen, taskmaster, test-agent
- 2 command workflows: ws-reset (branch reset), ship-and-babysit (PR pipeline)
- MCP servers: added playwright and context7
- Replaced generic 'agent' skill with specific role-based profiles
- All skills sync to both project and user scope for discovery
- P1: Separate approval replies from chat input via dedicated channel
- P1: Add quit-signal poll during active turns (cancel_check interval)
- P2: Guard /new against active turn (don't clear screen while thinking)
- P2: Drain stale approval-channel input before entering approval wait
- Add is_approval_reply helper to route yes/no/approve/deny through tx_approval
@45Harry
45Harry requested a review from a team July 14, 2026 10:34
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds an interactive Rust TUI chat command, expands Claude/OpenHuman configuration and skills, introduces Linux build automation and operational workflows, and updates supporting test imports, module exports, and the vendored tinycortex revision.

Changes

Assistant configuration and skill discovery

Layer / File(s) Summary
Assistant configuration and skill discovery
.claude/*, .openhuman/skills/*, .openhuman/trust, AGENTS.md, src/openhuman/skills/ops_discover.rs
Claude MCP/settings configuration, OpenHuman skill definitions, trust metadata, cross-tool skill discovery, and repository documentation are expanded.

Interactive chat

Layer / File(s) Summary
Chat command entry and terminal UI
Cargo.toml, src/core/*, src/openhuman/chat_cli/mod.rs
The CLI exposes openhuman chat, while the ratatui/crossterm TUI handles terminal setup, input, menus, model selection, scrolling, rendering, and responses.
Agent session and command orchestration
src/openhuman/chat_cli/mod.rs
The session creates the runtime and agent, routes chat and command events, handles approvals, switches models and sessions, and formats status, usage, memory, file, and tool results.

Automation and compatibility

Layer / File(s) Summary
Build automation and operational workflows
.github/workflows/build-core.yml, .openhuman/workflows/*
A Linux release build workflow and ship, monitoring, and workspace-reset workflow definitions are added.
Rust compatibility and dependency wiring
src/openhuman/**, vendor/tinycortex
Test-only imports, module re-exports, MCP tool exposure, and the vendored tinycortex revision are updated.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: feature, rust-core

Suggested reviewers: senamakel

Poem

I’m a rabbit with a terminal glow,
Tapping /chat where new messages flow.
Skills bloom, builds hop, approvals shine,
Models switch neatly in a colorful line.
Ship it safely—thump, thump, hooray!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too vague to describe the changeset and doesn’t indicate the main change. Replace it with a concise description of the primary change, e.g. “Add interactive chat CLI and TUI.”
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.

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.

Warning

⚠️ This pull request shows signs of AI-generated slop (description_diff_mismatch, ai_padded_prose). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72271114a5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/core/tui.rs
Comment on lines +352 to +354
if is_approval_reply(&text) {
let _ = tx_approval.send(text.clone());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop approval replies from becoming chat turns

When an approval prompt is active, typing yes/no sends the text to tx_approval, but this branch then falls through to Action::Send(text) for non-slash input. The main loop is still blocked in the current agent turn, so after the approval is applied it will process that queued yes/no as a brand-new user message, causing an unintended extra agent turn and transcript pollution. Return Action::Continue after sending an approval reply.

Useful? React with 👍 / 👎.

Comment on lines +234 to +237
if prompted_request_id.as_deref() != Some(request_id.as_str()) {
// Drain any stale input queued before this approval request
while rx_approval.try_recv().is_ok() {}
let _ = tx_resp.send(format_cli_approval_prompt(&gate, &request_id));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve pending approval replies across poll ticks

During an active tool approval, this drain can discard valid replies: wait_for_cli_approval_reply is recreated whenever the sibling cancel_check.tick() branch wins in the surrounding tokio::select!, so prompted_request_id resets and a yes/no typed after the prompt but before the next recreated future polls is treated as stale and removed. In that scenario the tool remains parked and the user sees repeated approval prompts despite having answered.

Useful? React with 👍 / 👎.

Comment thread .claude/mcp.json
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["@modelcontextprotocol/server-filesystem", "/home/harry"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove the personal home directory from MCP config

Committing a filesystem MCP server rooted at /home/harry makes this project config non-portable and, on any machine where that path exists, exposes an entire personal home directory rather than the repo/workspace to the assistant. This should be scoped to a project-relative path or left for user-local, gitignored configuration so other contributors do not inherit a broken or over-broad filesystem server.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Nitpick comments (3)
src/core/tui.rs (2)

88-100: 🩺 Stability & Availability | 🔵 Trivial | ⚖️ Poor tradeoff

No panic-safety net for terminal restoration.

Cleanup (leave alternate screen, disable raw mode, restore cursor) only runs on normal return from the render loop. A panic anywhere in render/handle_key would unwind past this and leave the user's terminal stuck in raw/alternate-screen mode. Consider installing a panic hook (or a Drop guard) that restores the terminal before the default panic message prints.

Also applies to: 163-166

🤖 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 `@src/core/tui.rs` around lines 88 - 100, Update the terminal setup and render
loop around Terminal::new, render, and handle_key to install panic-safe cleanup
that leaves the alternate screen, disables raw mode, and restores the cursor
before panic reporting. Ensure the cleanup runs both during normal shutdown and
when a panic unwinds, without suppressing the original panic.

175-451: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

New file has zero test coverage and exceeds the ~500-line guideline.

tui.rs is a brand-new ~701-line file with no #[cfg(test)] module at all. handle_key, filtered_cmds, and is_approval_reply are pure functions over App/KeyEvent and are cheap to unit-test without a real terminal. As per coding guidelines, "Keep files preferably at or below approximately 500 lines," and based on learnings, "PRs require at least 80% coverage on changed lines" — this file currently has neither.

🤖 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 `@src/core/tui.rs` around lines 175 - 451, Add unit tests for the pure
input-handling helpers handle_key, filtered_cmds, and is_approval_reply,
covering command filtering, approval replies, navigation, editing, and command
submission behavior without requiring a real terminal. Include a #[cfg(test)]
module in tui.rs and ensure changed-line coverage meets the project’s 80%
requirement. Reduce tui.rs below the approximately 500-line guideline by
extracting cohesive TUI logic into an appropriate module while preserving
existing behavior.

Sources: Coding guidelines, Learnings

src/openhuman/chat_cli/mod.rs (1)

510-545: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Coverage gap on the core session/approval logic.

Only two small helpers are covered; the async session loop, approval-reply handling, and all handle_* command dispatchers (the exact area with the critical bug flagged above) have no tests. Based on learnings, "PRs require at least 80% coverage on changed lines" — this file is far below that on its riskiest logic.

🤖 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 `@src/openhuman/chat_cli/mod.rs` around lines 510 - 545, Expand the tests
module beyond rewrite_chat_provider_model and format_cli_approval_decision to
cover the async session loop, approval-reply handling, and each handle_* command
dispatcher in the surrounding CLI implementation. Exercise successful, rejected,
and edge-case paths—especially the critical approval flow—and ensure the added
tests bring changed-line coverage to at least 80% without altering production
behavior.

Source: Learnings

🤖 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 @.claude/mcp.json:
- Around line 12-16: Replace the hardcoded /home/harry path in the filesystem
MCP configuration with a portable project-appropriate path or configurable
variable that resolves for each developer’s environment. Keep the filesystem
server entry and its intended access scope unchanged without referencing a
personal home directory.
- Around line 7-31: Add the non-interactive auto-confirm flag to the npx
argument arrays for the git, filesystem, github, and playwright MCP entries in
the MCP configuration, matching the existing context7 entry while preserving
each package name and command.

In @.claude/settings.json:
- Around line 15-39: Update the permissions entries in the permissions object:
replace the noncanonical FileRead allow rule with Read, and replace Delete in
the ask list with Edit so file access and write/delete operations match Claude
Code’s canonical tool names. Preserve the existing Bash, Read-related, and other
permission patterns.

In @.github/workflows/build-core.yml:
- Around line 22-26: Update the Checkout step using actions/checkout@v7 to set
persist-credentials to false in its with configuration, while preserving the
existing fetch-depth and recursive submodule settings.

In @.openhuman/skills/mobile-agent/SKILL.md:
- Line 4: Move when_to_use from the top-level frontmatter into the structured
metadata consumed by WorkflowFrontmatter, preserving its value and ensuring it
no longer lands in extra. Only add a dedicated typed field instead if the
existing consumers require top-level access, wiring that field through all
relevant parsing and consumption paths.

In @.openhuman/skills/pr-manager/SKILL.md:
- Around line 13-26: Make PR branch and remote safety explicit in both
workflows: in .openhuman/skills/pr-manager/SKILL.md lines 13-26, add preflight
validation requiring upstream/main as the base and verifying the target branch
and remote before checkout, push, or force-with-lease; in
.openhuman/skills/pr-manager-lite/SKILL.md lines 17-24, require pushes to origin
only and explicitly reject main as the target branch.
- Line 4: Remove the unsupported when_to_use key from the SKILL.md frontmatter
for the pr-manager skill, leaving the remaining frontmatter unchanged; do not
add loader support unless explicitly required.

In `@AGENTS.md`:
- Around line 17-18: The AGENTS.md skill documentation understates the contents
of .openhuman/skills/. Update AGENTS.md lines 17-18 to reflect the actual total
or explicitly identify the 11 listed bundles as a subset, and update lines
354-386 to include the newly added skills such as deploy-agent, designguru,
dev-agent, and memory-keeper or clearly scope the list to that subset; keep both
sections consistent.

In `@src/core/tui.rs`:
- Around line 319-354: Return Action::Continue immediately after sending an
approval reply through tx_approval in the Enter-key handling path, preventing it
from falling through to Action::Send(text) and being forwarded as a new agent
turn. Preserve the existing approval dispatch behavior for is_approval_reply
while leaving normal input handling unchanged.
- Around line 594-598: Update the cursor positioning logic in the rendering
block to derive the horizontal offset from the display width of the text prefix
before app.cursor, rather than using app.cursor as a byte-based column. Preserve
the existing menu/model_popup guard and bounds clamping while using the rendered
substring’s width for cx.
- Around line 530-562: The msgs_to_items and render_status functions incorrectly
embed ANSI escape sequences in raw text, so colors are rendered literally;
replace ansi_str-based text construction with ratatui styled Span/Line elements,
preserving the existing sender colors, labels, message layout, and status dot
appearance.

In `@src/openhuman/chat_cli/mod.rs`:
- Around line 27-33: The chat flow lacks entry and exit logging with a stable
correlation field. In src/openhuman/chat_cli/mod.rs:27-33, update
run_chat_command/run_interactive_session to log session start and a matching
exit before returning, including cli_thread_id; src/core/cli.rs:64-67 requires
no direct change once the root log exposes that field, while
src/core/cli.rs:88-88 may optionally add a debug dispatch log matching the agent
branch.
- Around line 1-33: Move the chat session loop, approval handling, command
handlers, and formatting helpers out of chat_cli’s mod.rs into a dedicated
session module, such as session.rs, preserving run_chat_command’s behavior and
public API. Update module declarations and imports so mod.rs contains only the
session module declaration and re-export of run_chat_command; split additional
approval or command logic into submodules only if needed.
- Around line 118-162: In the active-turn handling around
`wait_for_cli_approval_reply`, create and pin the approval-wait future before
entering the `tokio::select!` loop so timer ticks do not recreate it or reset
its state. After receiving `CliTurnSignal::ApprovalHandled`, replace and repin
the waiter for the next approval; preserve the existing `Quit` and
turn-completion behavior.

---

Nitpick comments:
In `@src/core/tui.rs`:
- Around line 88-100: Update the terminal setup and render loop around
Terminal::new, render, and handle_key to install panic-safe cleanup that leaves
the alternate screen, disables raw mode, and restores the cursor before panic
reporting. Ensure the cleanup runs both during normal shutdown and when a panic
unwinds, without suppressing the original panic.
- Around line 175-451: Add unit tests for the pure input-handling helpers
handle_key, filtered_cmds, and is_approval_reply, covering command filtering,
approval replies, navigation, editing, and command submission behavior without
requiring a real terminal. Include a #[cfg(test)] module in tui.rs and ensure
changed-line coverage meets the project’s 80% requirement. Reduce tui.rs below
the approximately 500-line guideline by extracting cohesive TUI logic into an
appropriate module while preserving existing behavior.

In `@src/openhuman/chat_cli/mod.rs`:
- Around line 510-545: Expand the tests module beyond
rewrite_chat_provider_model and format_cli_approval_decision to cover the async
session loop, approval-reply handling, and each handle_* command dispatcher in
the surrounding CLI implementation. Exercise successful, rejected, and edge-case
paths—especially the critical approval flow—and ensure the added tests bring
changed-line coverage to at least 80% without altering production behavior.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 66acabac-d100-4310-b24e-f4e084f9c088

📥 Commits

Reviewing files that changed from the base of the PR and between 8c37dfd and 7227111.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (48)
  • .claude/mcp.json
  • .claude/settings.json
  • .github/workflows/build-core.yml
  • .openhuman/skills/architectobot/SKILL.md
  • .openhuman/skills/browser/SKILL.md
  • .openhuman/skills/build-agent/SKILL.md
  • .openhuman/skills/code/SKILL.md
  • .openhuman/skills/codecrusher/SKILL.md
  • .openhuman/skills/config/SKILL.md
  • .openhuman/skills/debug/SKILL.md
  • .openhuman/skills/deploy-agent/SKILL.md
  • .openhuman/skills/designguru/SKILL.md
  • .openhuman/skills/dev-agent/SKILL.md
  • .openhuman/skills/memory-keeper/SKILL.md
  • .openhuman/skills/memory/SKILL.md
  • .openhuman/skills/mobile-agent/SKILL.md
  • .openhuman/skills/plan/SKILL.md
  • .openhuman/skills/pr-manager-lite/SKILL.md
  • .openhuman/skills/pr-manager/SKILL.md
  • .openhuman/skills/pr-reviewer/SKILL.md
  • .openhuman/skills/qualityqueen/SKILL.md
  • .openhuman/skills/review/SKILL.md
  • .openhuman/skills/search/SKILL.md
  • .openhuman/skills/taskmaster/SKILL.md
  • .openhuman/skills/test-agent/SKILL.md
  • .openhuman/skills/voice/SKILL.md
  • .openhuman/trust
  • .openhuman/workflows/ship-and-babysit/WORKFLOW.md
  • .openhuman/workflows/ws-reset/WORKFLOW.md
  • AGENTS.md
  • Cargo.toml
  • src/core/chat_cli.rs
  • src/core/cli.rs
  • src/core/mod.rs
  • src/core/tui.rs
  • src/openhuman/channels/providers/web/mod.rs
  • src/openhuman/chat_cli/mod.rs
  • src/openhuman/config/schema/load/mod.rs
  • src/openhuman/inference/local/service/ollama_admin/mod.rs
  • src/openhuman/inference/provider/reliable.rs
  • src/openhuman/mcp_server/tools/mod.rs
  • src/openhuman/memory/chat.rs
  • src/openhuman/memory/schema/mod.rs
  • src/openhuman/memory/tree_source/file.rs
  • src/openhuman/mod.rs
  • src/openhuman/sandbox/docker.rs
  • src/openhuman/skills/ops_discover.rs
  • vendor/tinycortex

Comment thread .claude/mcp.json
Comment on lines +7 to +31
"git": {
"type": "stdio",
"command": "npx",
"args": ["@modelcontextprotocol/server-git"]
},
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["@modelcontextprotocol/server-filesystem", "/home/harry"]
},
"github": {
"type": "stdio",
"command": "npx",
"args": ["@modelcontextprotocol/server-github"]
},
"playwright": {
"type": "stdio",
"command": "npx",
"args": ["@playwright/mcp@latest"]
},
"context7": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
}

Copy link
Copy Markdown
Contributor

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

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

echo "=== .claude/mcp.json ==="
cat -n .claude/mcp.json

echo
echo "=== npx usage from local environment (if available) ==="
if command -v npx >/dev/null 2>&1; then
  npx --help 2>/dev/null | sed -n '1,120p'
else
  echo "npx not available in sandbox"
fi

Repository: tinyhumansai/openhuman

Length of output: 2152


🌐 Web query:

npx -y --yes default install confirmation non-interactive prompts documentation

💡 Result:

To bypass the interactive installation confirmation prompt when using npx, you can use the --yes (or -y) flag [1][2][3]. By default, modern versions of npm (starting from version 7) prompt the user before installing packages that are not present in the local project dependencies [3][4]. Adding --yes to your npx command explicitly instructs it to proceed with the installation without requesting user confirmation, making it suitable for non-interactive environments such as CI/CD pipelines or automated scripts [1][4]. For example: npx --yes Alternatively, if you are working in an environment where you cannot easily modify the command arguments, you can set the environment variable npm_config_yes to true to achieve the same effect: npm_config_yes=true npx [4]

Citations:


Add -y to the remaining npx MCP entries. git, filesystem, github, and playwright can prompt for package install confirmation and block non-interactive startup; context7 already avoids that.

🤖 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 @.claude/mcp.json around lines 7 - 31, Add the non-interactive auto-confirm
flag to the npx argument arrays for the git, filesystem, github, and playwright
MCP entries in the MCP configuration, matching the existing context7 entry while
preserving each package name and command.

Comment thread .claude/mcp.json
Comment on lines +12 to +16
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["@modelcontextprotocol/server-filesystem", "/home/harry"]
},

Copy link
Copy Markdown
Contributor

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

Hardcoded user-specific path /home/harry.

This grants filesystem MCP access to a specific developer's home directory. It won't resolve for other contributors/machines and, if this is meant to be a shared project config, may unintentionally scope broad filesystem access to a personal directory.

🔧 Suggested fix
-      "args": ["`@modelcontextprotocol/server-filesystem`", "/home/harry"]
+      "args": ["`@modelcontextprotocol/server-filesystem`", "${PROJECT_ROOT}"]
🤖 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 @.claude/mcp.json around lines 12 - 16, Replace the hardcoded /home/harry
path in the filesystem MCP configuration with a portable project-appropriate
path or configurable variable that resolves for each developer’s environment.
Keep the filesystem server entry and its intended access scope unchanged without
referencing a personal home directory.

Comment thread .claude/settings.json
Comment on lines +15 to 39
"permissions": {
"allow": [
{ "tool": "Bash", "command": "git *" },
{ "tool": "Bash", "command": "npm *" },
{ "tool": "Bash", "command": "pnpm *" },
{ "tool": "Bash", "command": "cargo *" },
{ "tool": "Read" },
{ "tool": "Glob" },
{ "tool": "Grep" },
{ "tool": "FileRead" }
],
"deny": [
{ "tool": "Bash", "command": "rm -rf /" },
{ "tool": "Bash", "command": "sudo *" },
{ "tool": "Bash", "command": "chmod 777 *" }
],
"ask": [
{ "tool": "Bash", "command": "curl *" },
{ "tool": "Bash", "command": "wget *" },
{ "tool": "Write" },
{ "tool": "Edit" },
{ "tool": "Delete" }
],
"defaultMode": "prompt"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does Claude Code have a "Delete" tool or "FileRead" tool in its permissions system?

💡 Result:

Yes, Claude Code includes a FileReadTool in its toolset, and it maintains a comprehensive permissions system that governs all tool usage, including file operations [1][2][3]. The FileReadTool is a core component of Claude Code's file operations, designed for reading file contents (including support for images, PDFs, and Jupyter notebooks) [3][4][5]. Regarding a "Delete" tool, while there is no specific standalone "FileDeleteTool" listed in the standard core file operations, Claude Code includes a TeamDeleteTool for managing agent teams [3][4]. For general file deletion, the agent typically utilizes the BashTool, which allows for shell command execution (e.g., executing rm) [3][5]. Because the BashTool is a high-capability tool, it is subject to rigorous security checks within the unified permission system, which handles all tool requests through a multi-stage validation pipeline [1][2]. The permissions system is designed with "fail-closed" defaults and uses a granular engine to evaluate tool usage based on configured rules, workspace trust, and mode-based defaults (such as plan, auto, or interactive modes) [6][7][5]. Every tool, including those for file operations or team management, must pass through this permission check, which can deny, approve, or require user confirmation depending on the safety evaluation of the requested operation [6][1][2].

Citations:


🌐 Web query:

Official Claude Code permission tool names FileRead Delete permissions settings.json

💡 Result:

Claude Code uses specific tool names and syntax within the settings.json file to manage permissions, including Read and Edit (which covers file deletions and other write operations) [1][2][3]. Permission Rules To configure permissions, you define arrays under the permissions object in your settings.json (at ~/.claude/settings.json for global settings or .claude/settings.json for project-specific settings) [2][4][3]. 1. Tool Names: You reference tools by their specific names, such as Read, Edit, Bash, or WebFetch [1][3]. 2. Rule Format: Rules follow the format ToolName(specifier) [1]. - Read permissions: Use Read(path-pattern) to control file access [1][3]. - Write/Delete permissions: Use Edit(path-pattern) to control file modifications, including writes, deletions, and moves [1]. 3. Deny/Allow Lists: - deny: Explicitly blocks tools or specific paths, even if they would otherwise be permitted [2][3]. Example: "deny": ["Read(./.env)", "Read(./secrets/)"] [2][3]. - allow: Pre-approves tools or specific paths to avoid prompts [2][4]. Management Interface Beyond editing settings.json directly, you can manage these rules interactively by running the /permissions command in the Claude Code CLI [5][6]. This interface allows you to view existing rules and manage permissions for the current session or project [5][6]. Important Notes on Enforcement - Evaluation Order: Rules are processed in the order deny -> ask -> allow. If a rule matches, the first applicable outcome (typically deny) takes precedence [3]. - Security Limitations: While the documentation outlines this permission system, users have reported issues where certain deny patterns for Read and Write/Edit tools are not consistently enforced in some versions [7][8][9]. For critical security, consider that bypassPermissions or defaultMode: "bypassPermissions" will ignore standard permission checks regardless of deny rules (though explicit ask rules may still trigger as a circuit breaker) [10][11][12][2]. Always verify your configuration using the /permissions UI [5][6].

Citations:


Replace FileRead and Delete with canonical Claude Code tools
FileRead and Delete won't match the permission rules here. Use Read(...) for file access and Edit(...) for write/delete gating.

🤖 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 @.claude/settings.json around lines 15 - 39, Update the permissions entries
in the permissions object: replace the noncanonical FileRead allow rule with
Read, and replace Delete in the ask list with Edit so file access and
write/delete operations match Claude Code’s canonical tool names. Preserve the
existing Bash, Read-related, and other permission patterns.

Comment on lines +22 to +26
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 1
submodules: recursive

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Fetch the latest release version of actions/checkout
gh release list --repo actions/checkout --limit 1

Repository: tinyhumansai/openhuman

Length of output: 202


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the workflow snippet and related checkout usages.
git ls-files .github/workflows/build-core.yml .github/workflows/*.yml | sed -n '1,20p'
echo
cat -n .github/workflows/build-core.yml | sed -n '1,120p'
echo
rg -n "actions/checkout@v[0-9]+" .github/workflows -S

Repository: tinyhumansai/openhuman

Length of output: 6820


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# See whether checkout hardening is already used elsewhere.
rg -n -C 2 "persist-credentials:\s*false|uses: actions/checkout@v7|uses: actions/checkout@v4" .github/workflows -S

Repository: tinyhumansai/openhuman

Length of output: 25330


Set persist-credentials: false on the checkout step

actions/checkout@v7 is fine here, but this job should disable credential persistence so the token isn’t left in git config.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 22-26: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 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 @.github/workflows/build-core.yml around lines 22 - 26, Update the Checkout
step using actions/checkout@v7 to set persist-credentials to false in its with
configuration, while preserving the existing fetch-depth and recursive submodule
settings.

Source: Linters/SAST tools

---
name: mobile-agent
description: Android and iOS development specialist
when_to_use: Working on mobile-specific features or configuration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files '.openhuman/skills/mobile-agent/SKILL.md' || true
printf '\n== search WorkflowFrontmatter and when_to_use ==\n'
rg -n "WorkflowFrontmatter|when_to_use|metadata" .openhuman -g '!**/node_modules/**' || true
printf '\n== find likely schema files ==\n'
fd -a 'WorkflowFrontmatter|frontmatter|skill' .openhuman . 2>/dev/null | head -n 200

Repository: tinyhumansai/openhuman

Length of output: 5543


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the skill file and nearby frontmatter schema definitions.
printf '\n== skill file ==\n'
cat -n .openhuman/skills/mobile-agent/SKILL.md | sed -n '1,80p'

printf '\n== candidate schema files ==\n'
fd -a '.*(frontmatter|workflow|skill).*' .openhuman 2>/dev/null | head -n 200

printf '\n== search for typed frontmatter definition ==\n'
rg -n "type WorkflowFrontmatter|interface WorkflowFrontmatter|WorkflowFrontmatter" .openhuman -g '!**/node_modules/**' || true

Repository: tinyhumansai/openhuman

Length of output: 2535


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== search frontmatter parsers / skill loaders ==\n'
rg -n "frontmatter|gray-matter|yaml|allowed-tools|when_to_use|SKILL\.md|WORKFLOW\.md|skills_data|skill registry|workflow" src app tests .openhuman -g '!**/node_modules/**' || true

printf '\n== inspect likely skill registry files ==\n'
sed -n '1,240p' src/openhuman/skill_registry/mod.rs 2>/dev/null || true
sed -n '1,240p' src/openhuman/skill_registry/lib.rs 2>/dev/null || true
sed -n '1,240p' src/openhuman/skill_registry/agent/skill_setup/mod.rs 2>/dev/null || true
sed -n '1,240p' src/openhuman/skill_runtime/mod.rs 2>/dev/null || true
sed -n '1,240p' src/openhuman/skill_runtime/agent/skill_executor/mod.rs 2>/dev/null || true

Repository: tinyhumansai/openhuman

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== exact when_to_use definitions ==\n'
rg -n "when_to_use" src app .openhuman -g '!**/node_modules/**' | head -n 200

printf '\n== exact frontmatter struct/type definitions ==\n'
rg -n "struct .*Frontmatter|type .*Frontmatter|interface .*Frontmatter|when_to_use:|allowed-tools:|allowed_tools:" src app .openhuman -g '!**/node_modules/**' | head -n 200

printf '\n== inspect dispatch and registry slices ==\n'
sed -n '220,320p' src/openhuman/mcp_server/tools/dispatch.rs
sed -n '1,220p' src/openhuman/skill_registry/mod.rs 2>/dev/null || true
sed -n '1,220p' src/openhuman/skill_registry/agent/skill_setup/mod.rs 2>/dev/null || true
sed -n '1,240p' src/openhuman/skill_runtime/agent/skill_executor/mod.rs 2>/dev/null || true

Repository: tinyhumansai/openhuman

Length of output: 50378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== WorkflowFrontmatter and related types ==\n'
sed -n '1,180p' src/openhuman/skills/ops_types.rs

printf '\n== skill create/render paths around when_to_use ==\n'
sed -n '300,620p' src/openhuman/skills/ops_create.rs

printf '\n== registry parsing/normalization around when_to_use ==\n'
sed -n '180,280p' src/openhuman/skills/registry.rs

Repository: tinyhumansai/openhuman

Length of output: 23364


Keep when_to_use inside the structured metadata

WorkflowFrontmatter only exposes typed fields for name, description, license, compatibility, platforms, metadata, allowed-tools, and triggers; a top-level when_to_use falls into extra. Move it under metadata, or add a dedicated typed field and wire consumers to it.

🤖 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 @.openhuman/skills/mobile-agent/SKILL.md at line 4, Move when_to_use from the
top-level frontmatter into the structured metadata consumed by
WorkflowFrontmatter, preserving its value and ensuring it no longer lands in
extra. Only add a dedicated typed field instead if the existing consumers
require top-level access, wiring that field through all relevant parsing and
consumption paths.

Comment thread src/core/tui.rs
Comment on lines +530 to +562
fn msgs_to_items(app: &App) -> Vec<ListItem<'static>> {
let mut items = Vec::new();
for m in &app.msgs {
let tag = match m.sender.as_str() {
"you" => ansi_str("you", CYAN),
"ai" | "assistant" => ansi_str("ai", Color::Green),
"system" => ansi_str("sys", Color::Gray),
_ => ansi_str(&m.sender, Color::Gray),
};
let mut first = true;
for line in m.content.split('\n') {
let text = if first {
format!(" {} {}", tag, line)
} else {
format!(" {}", line)
};
items.push(ListItem::new(Text::raw(text)).style(Style::default().bg(DARK_BG)));
first = false;
}
}
items
}

fn render_status(f: &mut Frame, app: &App, area: Rect) {
let msg = format!(
" {} Model: {} | Ctrl+C to quit | / for menu ",
ansi_str("●", Color::Green),
app.model_name
);
let para =
Paragraph::new(Text::raw(msg)).style(Style::default().bg(SURFACE).fg(Color::DarkGray));
f.render_widget(para, area);
}

Copy link
Copy Markdown
Contributor

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
set -euo pipefail

# Locate the relevant file and show the surrounding lines.
git ls-files src/core/tui.rs
wc -l src/core/tui.rs
sed -n '500,730p' src/core/tui.rs | cat -n

# Find all uses/definition of ansi_str.
rg -n "ansi_str|Text::raw|ListItem::new|Paragraph::new" src/core/tui.rs

Repository: tinyhumansai/openhuman

Length of output: 8555


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Identify the ratatui dependency version and inspect the second ansi_str area.
rg -n 'ratatui|ansi_str' Cargo.toml Cargo.lock src/core/tui.rs
sed -n '680,705p' src/core/tui.rs | cat -n

Repository: tinyhumansai/openhuman

Length of output: 1549


🌐 Web query:

ratatui 0.29 Text::raw ANSI escape sequences rendered as text ansi-to-tui crate documentation

💡 Result:

In Ratatui, the Text::raw method is used to create text without applying any Ratatui-specific styling [1][2]. It does not parse or render ANSI escape sequences [3][4][5]. If you pass a string containing ANSI escape codes to Text::raw, the terminal may attempt to interpret them directly as control characters when the buffer is rendered, which often results in incorrect character placement, broken formatting, or visual artifacts, as Ratatui manages style information separately within its Buffer and Cell structures [6][7][5]. To properly render ANSI-styled text in Ratatui, you should use the ansi-to-tui crate [8][4]. This crate is designed to parse bytes containing ANSI SGR (Select Graphic Rendition) escape sequences and convert them into a Ratatui Text object, correctly mapping colors and modifiers to Ratatui's Style system [8][9]. Key details regarding this approach: - Functionality: ansi-to-tui parses ANSI codes (such as those for bold, italic, and various color modes including 3/4-bit, 256-color, and 24-bit RGB) and produces a valid Ratatui Text or Line struct [8][9]. - Implementation: You can use the IntoText trait provided by the crate to convert your input directly [8][9]. - Usage Example: use ansi_to_tui::IntoText as _; let bytes = b"\x1b[31mRed Text\x1b[0m"; // Example ANSI encoded bytes let text = bytes.into_text.unwrap; // Converts to Ratatui Text // Now pass 'text' to a widget like Paragraph::new(text) Using this crate is the recommended way to handle ANSI-encoded strings in Ratatui applications [6][3][4].

Citations:


Use ratatui styles instead of raw ANSI escapes.

ansi_str injects literal \x1b[..m sequences into Text::raw, but ratatui treats that as plain text, so the sender tags and status dot won’t actually render with color. Build these as styled Spans/Lines instead.

🤖 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 `@src/core/tui.rs` around lines 530 - 562, The msgs_to_items and render_status
functions incorrectly embed ANSI escape sequences in raw text, so colors are
rendered literally; replace ansi_str-based text construction with ratatui styled
Span/Line elements, preserving the existing sender colors, labels, message
layout, and status dot appearance.

Comment thread src/core/tui.rs
Comment on lines +594 to +598
f.render_widget(Paragraph::new(text).style(style), inner);
if !app.menu && !app.model_popup {
let cx = inner.x + 1 + app.cursor as u16;
f.set_cursor_position((cx.min(area.right().saturating_sub(1)), inner.y));
}

Copy link
Copy Markdown
Contributor

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- src/core/tui.rs outline ---\n'
ast-grep outline src/core/tui.rs --view expanded || true

printf '\n--- relevant cursor/input symbols ---\n'
rg -n "cursor|input|unicode-width|UnicodeWidth" src/core/tui.rs src -g '*.rs' || true

printf '\n--- src/core/tui.rs excerpt around the cursor code ---\n'
sed -n '560,610p' src/core/tui.rs

printf '\n--- app definition / cursor type ---\n'
rg -n "struct App|cursor:|input:" src -g '*.rs' || true

Repository: tinyhumansai/openhuman

Length of output: 251


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- src/core/tui.rs outline ---'
ast-grep outline src/core/tui.rs --view expanded || true

echo
echo '--- relevant cursor/input symbols ---'
rg -n "cursor|input|unicode-width|UnicodeWidth" src/core/tui.rs src -g '*.rs' || true

echo
echo '--- src/core/tui.rs excerpt around the cursor code ---'
sed -n '560,610p' src/core/tui.rs

echo
echo '--- app definition / cursor type ---'
rg -n "struct App|cursor:|input:" src -g '*.rs' || true

Repository: tinyhumansai/openhuman

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- src/core/tui.rs lines 560-610 ---'
sed -n '560,610p' src/core/tui.rs

echo
echo '--- src/core/tui.rs AST outline (trimmed) ---'
ast-grep outline src/core/tui.rs --view expanded | sed -n '1,220p'

echo
echo '--- cursor/input definitions across src/core and likely app state ---'
rg -n "struct App|pub struct App|cursor: (usize|u16|usize)|input: String|cursor as u16|UnicodeWidthStr|unicode-width" src/core src -g '*.rs' -g '!target' || true

Repository: tinyhumansai/openhuman

Length of output: 6752


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- handle_key / cursor mutation logic ---'
sed -n '175,360p' src/core/tui.rs

echo
echo '--- app initialization and any cursor reset/update paths ---'
sed -n '80,175p' src/core/tui.rs

echo
echo '--- any direct cursor arithmetic elsewhere ---'
rg -n "app\.cursor|cursor\s*=" src/core/tui.rs -n

Repository: tinyhumansai/openhuman

Length of output: 10848


Cursor position should use display width, not byte offset. app.cursor advances in UTF-8 bytes, so the caret drifts for non-ASCII input; compute the column from the rendered substring width instead.

🤖 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 `@src/core/tui.rs` around lines 594 - 598, Update the cursor positioning logic
in the rendering block to derive the horizontal offset from the display width of
the text prefix before app.cursor, rather than using app.cursor as a byte-based
column. Preserve the existing menu/model_popup guard and bounds clamping while
using the rendered substring’s width for cx.

Comment on lines +1 to +33
//! `openhuman chat` — TUI-based interactive chat session.

use std::sync::mpsc;

use anyhow::{anyhow, Result};
use console::style;

use crate::core::tui::AgentCmd;
use crate::core::types::{approval_gate_boot_decision, HostKind};
use crate::openhuman::agent::turn_origin::{with_origin, AgentTurnOrigin};
use crate::openhuman::agent::Agent;
use crate::openhuman::approval::gate::{record_boot_state, ApprovalGateBootState};
use crate::openhuman::approval::{
parse_approval_reply, ApprovalChatContext, ApprovalDecision, ApprovalGate,
APPROVAL_CHAT_CONTEXT,
};
use crate::openhuman::config::ops::ModelSettingsPatch;
use crate::openhuman::config::rpc::load_and_apply_model_settings;
use crate::openhuman::config::Config;
use crate::openhuman::cost::{try_global, CostTracker};
use crate::openhuman::credentials::ops::clear_session;
use crate::openhuman::credentials::session_support::build_session_state;
use crate::openhuman::memory::ops::{ai_list_memory_files, memory_list_namespaces};
use crate::openhuman::memory::rpc_models::{EmptyRequest, ListMemoryFilesRequest};
use crate::openhuman::memory_conversations::list_threads;

pub fn run_chat_command(args: &[String]) -> Result<()> {
if args.iter().any(|a| a == "-h" || a == "--help") {
print_help();
return Ok(());
}
run_interactive_session()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Business logic belongs in a submodule, not mod.rs.

This mod.rs (~690 lines) holds the full session loop, approval handling, command handlers, and formatting helpers. As per coding guidelines, "src/openhuman/**/mod.rs: Keep mod.rs export-focused: only module declarations, re-exports, and the controller schema pair; do not put business logic there," and separately "Keep files preferably at or below approximately 500 lines." Move the orchestration/handlers into e.g. src/openhuman/chat_cli/session.rs (and maybe approval.rs/commands.rs), leaving mod.rs with just pub mod session; pub use session::run_chat_command;.

🤖 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 `@src/openhuman/chat_cli/mod.rs` around lines 1 - 33, Move the chat session
loop, approval handling, command handlers, and formatting helpers out of
chat_cli’s mod.rs into a dedicated session module, such as session.rs,
preserving run_chat_command’s behavior and public API. Update module
declarations and imports so mod.rs contains only the session module declaration
and re-export of run_chat_command; split additional approval or command logic
into submodules only if needed.

Source: Coding guidelines

Comment on lines +27 to +33
pub fn run_chat_command(args: &[String]) -> Result<()> {
if args.iter().any(|a| a == "-h" || a == "--help") {
print_help();
return Ok(());
}
run_interactive_session()
}

Copy link
Copy Markdown
Contributor

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

New interactive-chat flow lacks the guideline-mandated entry/branch logging across its call chain. The root cause is that run_chat_command/run_interactive_session never log session start, so every caller that dispatches into it is also silent, unlike sibling flows (e.g. the "agent" arm) that log before dispatching. As per coding guidelines, "New or changed flows must log entry and exit, branches, external calls, ... using stable grep-friendly prefixes and correlation fields."

  • src/openhuman/chat_cli/mod.rs#L27-L33: add an entry log (e.g. log::info!("[chat_cli] session started thread_id={cli_thread_id}")) in run_chat_command/run_interactive_session, and a matching exit log before returning.
  • src/core/cli.rs#L64-L67: once the root entry log exists, this empty-args default-to-chat branch is adequately covered by it; no separate change needed here beyond confirming the correlation field surfaces.
  • src/core/cli.rs#L88-L88: same — covered once the root log lands; optionally add a log::debug! before dispatch to match the "agent" arm's style for grep-ability at the dispatch site itself.
📍 Affects 2 files
  • src/openhuman/chat_cli/mod.rs#L27-L33 (this comment)
  • src/core/cli.rs#L64-L67
  • src/core/cli.rs#L88-L88
🤖 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 `@src/openhuman/chat_cli/mod.rs` around lines 27 - 33, The chat flow lacks
entry and exit logging with a stable correlation field. In
src/openhuman/chat_cli/mod.rs:27-33, update
run_chat_command/run_interactive_session to log session start and a matching
exit before returning, including cli_thread_id; src/core/cli.rs:64-67 requires
no direct change once the root log exposes that field, while
src/core/cli.rs:88-88 may optionally add a debug dispatch log matching the agent
branch.

Source: Coding guidelines

Comment on lines +118 to +162
let turn = with_origin(
origin,
APPROVAL_CHAT_CONTEXT
.scope(approval_ctx, active_agent.run_single(&msg)),
);
tokio::pin!(turn);
let mut cancel_check = tokio::time::interval(
std::time::Duration::from_millis(200),
);
loop {
tokio::select! {
_ = cancel_check.tick() => {
if tui_requested_quit(&rx_quit) {
log::debug!("[chat_cli] TUI quit during active turn; aborting");
break;
}
}
result = &mut turn => {
match result {
Ok(response) => {
let _ = tx_resp.send(response);
}
Err(e) => {
log::debug!("[chat_cli] agent turn failed: {e}");
let _ = tx_resp.send(format!("Error: {e}"));
}
}
break;
}
signal = wait_for_cli_approval_reply(
&rx_approval,
&rx_quit,
&tx_resp,
&cli_thread_id,
) => {
match signal {
CliTurnSignal::ApprovalHandled => continue,
CliTurnSignal::Quit => {
log::debug!("[chat_cli] TUI quit signal received during agent turn; cancelling session");
break;
}
}
}
}
}

Copy link
Copy Markdown
Contributor

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

🧩 Analysis chain

🏁 Script executed:

sed -n '1,340p' src/openhuman/chat_cli/mod.rs

Repository: tinyhumansai/openhuman

Length of output: 13948


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path
p = Path('src/openhuman/chat_cli/mod.rs')
for start,end in [(96,188),(213,287)]:
    print(f"\n--- lines {start}-{end} ---")
    for i,line in enumerate(p.read_text().splitlines(),1):
        if start <= i <= end:
            print(f"{i:4}: {line}")
PY

Repository: tinyhumansai/openhuman

Length of output: 9067


🏁 Script executed:

rg -n "wait_for_cli_approval_reply|tokio::pin!\(.*approval|ApprovalHandled" src/openhuman -g '*.rs'

Repository: tinyhumansai/openhuman

Length of output: 606


Pin the approval wait across select! iterations. src/openhuman/chat_cli/mod.rs:147-154, 213-239 Calling wait_for_cli_approval_reply(...) inline recreates that future whenever cancel_check.tick() wins, which resets prompted_request_id and can re-send the approval prompt while also draining a queued reply. Keep the approval waiter pinned outside the loop and replace it only after ApprovalHandled.

🤖 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 `@src/openhuman/chat_cli/mod.rs` around lines 118 - 162, In the active-turn
handling around `wait_for_cli_approval_reply`, create and pin the approval-wait
future before entering the `tokio::select!` loop so timer ticks do not recreate
it or reset its state. After receiving `CliTurnSignal::ApprovalHandled`, replace
and repin the waiter for the next approval; preserve the existing `Quit` and
turn-completion behavior.

@senamakel

Copy link
Copy Markdown
Member

Triage check-in: this PR has changes requested and the branch now conflicts with main, and the title/description don't make the intended scope clear. Are you still pursuing it? If so, please rebase, address the review feedback, and give it a descriptive title. No response in ~2 weeks and we'll close it to keep the queue tidy — it can always be reopened.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants