Skip to content

fix(agent): handle reasoning tags for #248 - #249

Open
collabflip wants to merge 1 commit into
HCF-STUDIOS:mainfrom
collabflip:fix/248-reasoning-tags
Open

fix(agent): handle reasoning tags for #248#249
collabflip wants to merge 1 commit into
HCF-STUDIOS:mainfrom
collabflip:fix/248-reasoning-tags

Conversation

@collabflip

@collabflip collabflip commented Jul 26, 2026

Copy link
Copy Markdown

Description

Fixes issue #248 regarding reasoning tag handling in agent responses.

Changes

  • Updated reasoning tag parsing/suppression behavior in agent output.
  • Ensured unclosed or stray tags do not leak raw thinking into user replies.

Testing

  • Tested locally in agent runtime environment.

Summary by CodeRabbit

  • New Features
    • Added interactive phone and work agent command-line tools.
    • Added session and task timing, task history, CSV persistence, and invoice generation at a $75 hourly rate.
    • Added audit logging and verification for agent sessions, chat activity, and work tracking.
    • Added scripts to launch audited chat sessions and manage the supporting gateway.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds audited Bash workflows for OpenHermit gateway chat, phone-agent interaction, and work-task tracking. A JSONL ledger records session, agent, task, invoice, and verification events.

Changes

Audited agent workflows

Layer / File(s) Summary
Gateway chat audit flow
start-hermit-audit.sh, run-with-audit.sh, .veilpiercer.jsonl
Gateway readiness, Hermit chat lifecycle logging, shutdown, and audit verification are added.
Phone agent interaction
phone-agent.sh, .veilpiercer.jsonl
An interactive phone-agent loop logs messages and responses, supports verification, and records agent termination.
Work-agent task tracking
work-agent.sh, .veilpiercer.jsonl
Task timing, CSV persistence, task listing, invoice calculation, lifecycle logging, and audit verification are added.

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

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant OpenHermit
  participant AgentScripts
  participant Veilpiercer
  Operator->>AgentScripts: start audited workflow
  AgentScripts->>OpenHermit: start gateway or chat
  OpenHermit-->>AgentScripts: provide chat interaction
  AgentScripts->>Veilpiercer: log session and agent events
  AgentScripts->>Veilpiercer: verify audit ledger
  Veilpiercer-->>Operator: verification result
Loading

Poem

A bunny hops through logs so neat,
With chat and tasks in timed retreat.
Messages bloom, invoices gleam,
Audit trails guard every stream.
Hop, hop—verified!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title mentions reasoning-tag handling, but the PR actually adds audit/workflow Bash scripts and a ledger. Rename the title to match the delivered changes, e.g. reference the new audit and agent workflow scripts.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 unit tests (beta)
  • Create PR with unit tests

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 has been flagged as potential spam (other-spam) by CodeRabbit slop detection and should be reviewed carefully.

@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: 16

🤖 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 @.veilpiercer.jsonl:
- Around line 11-17: Prevent raw runtime messages from being committed by moving
the .veilpiercer.jsonl ledger outside the repository or sanitizing it to retain
only allowlisted fields, and add the runtime file pattern to .gitignore.
Preserve necessary audit metadata such as timestamps, event types, and hashes
without persisting complete USER_MSG or AGENT_RESPONSE content.

In `@phone-agent.sh`:
- Around line 8-16: Update the interactive loop around `AGENT_END` and
`veilpiercer verify` by adding an idempotent cleanup function and registering it
with traps for Ctrl-C, SIGTERM, and related termination signals. Ensure cleanup
logs the session end, runs audit verification once, and preserves or propagates
verification failures across both typed `exit` and interrupted termination
paths.
- Line 6: Update the audit command invocations in phone-agent.sh, including the
AGENT_START log and the additional veilpiercer log/verify calls, to check each
command’s exit status. Immediately terminate with a nonzero status when any
audit operation fails, ensuring the script cannot continue or report successful
verification after a failure.
- Around line 23-24: Update the USER_MSG logging in the message-processing flow
to avoid persisting raw phone-message content; replace the sanitized message
payload with the approved redaction, metadata, or digest mechanism. Do not rely
on quote removal or truncation as privacy protection, and preserve the existing
count/context information in veilpiercer log.
- Around line 8-10: Update the input loop around the read command to use IFS=
read -r -p "You: " msg and check its return status before processing msg. On
EOF, route execution through the existing normal cleanup path instead of logging
or appending another USER_MSG event; preserve the current exit-command handling
for valid input.

In `@start-hermit-audit.sh`:
- Line 12: Replace the predictable /tmp/gateway.log path in the background
start:gateway command with a log file created via mktemp, retain its path for
subsequent use, and remove the temporary log during the script’s cleanup
handling.
- Around line 18-23: The readiness probe in the loop using curl against
/api/agents must validate an actual successful gateway response rather than
merely a completed HTTP request. Replace the protected endpoint with a public
health endpoint or provide the required authorization, enable HTTP failure
detection, and add connection and overall request timeouts before logging
GATEWAY_READY.
- Around line 48-52: Preserve nonzero chat and verification exits across both
audit wrappers. In start-hermit-audit.sh, replace the hermit chat || true flow
with status capture, log a failure or abort outcome instead of unconditional
CHAT_END success, perform cleanup, and exit nonzero. In run-with-audit.sh,
capture chat and verification statuses, use an EXIT trap to record lifecycle
completion, and propagate any failure; update both referenced sites accordingly.
- Around line 12-14: Add an EXIT trap immediately after assigning GATEWAY_PID
that terminates the gateway, waits for its completion, and cleans up on normal
exits, errors, or signals. Apply the same cleanup behavior to the later gateway
startup block around the second GATEWAY_PID assignment, preserving the existing
straight-line flow.

In `@work-agent.sh`:
- Line 20: Update the command dispatch case for time so it accepts the
documented task argument, including prompts with spaces, and passes that task to
the timing workflow. Keep the help text and existing behavior for other commands
unchanged.
- Around line 29-35: Update the time command handling to check for an existing
active timer before writing .current_task or .task_start_time. If a timer is
active, refuse to start the new task and leave the existing timer state
unchanged; otherwise preserve the current task initialization, TASK_STARTED
logging, and timing output.
- Line 49: Update the task persistence and parsing around the work_tasks.csv
append and the awk processing near line 72 so task names containing commas
cannot shift the duration field. Use a CSV-aware serializer/parser or replace
the internal format with a validated unambiguous delimiter, and ensure invoice
totals continue reading the actual MINS value.
- Line 11: Update work-agent.sh so failures from both veilpiercer log and
veilpiercer verify propagate as nonzero exits instead of being ignored. Remove
or defer the exit success message until after veilpiercer verify completes
successfully, and report success only on that successful verification path.
- Line 14: Update both interactive input reads in work-agent.sh to use IFS= read
-r -p, preserving literal backslashes in command and task-name values before
they are written to .current_task, work_tasks.csv, and veilpiercer logs.
- Line 14: Update the command-reading loop around read in the work-agent script
to detect EOF or another failed read, then route through the existing
WORK_AGENT_END/session-finalization path so verification and cleanup still run
before exiting. Preserve normal command handling for successful reads and ensure
the EOF path terminates with the appropriate exit status after finalization.
- Around line 32-33: Update work-agent.sh to create and use a private,
permission-restricted state directory for temporary files such as .current_task
and .task_start_time, rather than writing predictable paths in the caller’s
working directory. Also change the work_tasks.csv append logic to resolve the
file from the script’s installed canonical location instead of the current
working directory.
🪄 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 Plus

Run ID: cf99ccf8-f6b8-4f51-8c8f-394e403d8510

📥 Commits

Reviewing files that changed from the base of the PR and between 9c9c519 and 5ba35ac.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • .veilpiercer.jsonl
  • phone-agent.sh
  • run-with-audit.sh
  • start-hermit-audit.sh
  • work-agent.sh

Comment thread .veilpiercer.jsonl
Comment on lines +11 to +17
{"timestamp": "2026-07-26T20:12:42.292029+00:00", "event": "USER_MSG", "message": "[1] what can we do", "prev_hash": "b91516160c629a5b58218c3f99a1e14ba8c5266881106015788b4210d7e1699b", "hash": "3a35c9ff6a77e1949750b89ee9dfd0d530fe74354ddd64fd6b0ef0838abcdc59"}
{"timestamp": "2026-07-26T20:12:42.383690+00:00", "event": "AGENT_RESPONSE", "message": "Response #1", "prev_hash": "3a35c9ff6a77e1949750b89ee9dfd0d530fe74354ddd64fd6b0ef0838abcdc59", "hash": "cd6a7f4f690ce3b37dfe3e6697a692159bc142789c3d5ed3bd884135be4ea4c5"}
{"timestamp": "2026-07-26T20:12:51.750472+00:00", "event": "USER_MSG", "message": "[2] cd ~/openhermit", "prev_hash": "cd6a7f4f690ce3b37dfe3e6697a692159bc142789c3d5ed3bd884135be4ea4c5", "hash": "24aa07350026576b1ea6462102435a15e58fb45a48cd6086eededb0b036572fa"}
{"timestamp": "2026-07-26T20:12:51.838487+00:00", "event": "AGENT_RESPONSE", "message": "Response #2", "prev_hash": "24aa07350026576b1ea6462102435a15e58fb45a48cd6086eededb0b036572fa", "hash": "b3353c69175d479c62769af4b2635d3045c6c5ad2493fac7ba8f93a1137a5811"}
{"timestamp": "2026-07-26T20:12:51.950403+00:00", "event": "USER_MSG", "message": "[3] ", "prev_hash": "b3353c69175d479c62769af4b2635d3045c6c5ad2493fac7ba8f93a1137a5811", "hash": "ca6ae05ca1e9335329e0884213c2f7186db8432a4d6d1342dfc61226b37f1d06"}
{"timestamp": "2026-07-26T20:12:52.044142+00:00", "event": "AGENT_RESPONSE", "message": "Response #3", "prev_hash": "ca6ae05ca1e9335329e0884213c2f7186db8432a4d6d1342dfc61226b37f1d06", "hash": "01923ebe660007780a850b54fb752b2d417d38c8f47648200d762e8a5b9dfec6"}
{"timestamp": "2026-07-26T20:12:52.140421+00:00", "event": "USER_MSG", "message": "[4] cat > phone-agent.sh << 'EOF'", "prev_hash": "01923ebe660007780a850b54fb752b2d417d38c8f47648200d762e8a5b9dfec6", "hash": "e0dd0c7543bedc188bd7f48ad455f0b88e7ba7cea97b2620f095681355737ecb"}

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

Keep raw runtime messages out of the repository.

These USER_MSG records persist complete user input—including shell commands and local paths. Future prompts could contain credentials or PII, which would then remain in Git history. Store the ledger outside the repository or redact/allowlist message fields, and add the runtime file to .gitignore.

🤖 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 @.veilpiercer.jsonl around lines 11 - 17, Prevent raw runtime messages from
being committed by moving the .veilpiercer.jsonl ledger outside the repository
or sanitizing it to retain only allowlisted fields, and add the runtime file
pattern to .gitignore. Preserve necessary audit metadata such as timestamps,
event types, and hashes without persisting complete USER_MSG or AGENT_RESPONSE
content.

Comment thread phone-agent.sh
echo "║ OpenHermit Phone Agent + Audit Logging ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""
veilpiercer log "AGENT_START" "Phone agent session started"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Propagate audit command failures.

If veilpiercer log fails, the agent continues without recording the event. If veilpiercer verify fails, the script still breaks and exits as though verification succeeded. This violates the audit contract used by run-with-audit.sh Lines 9-20 and work-agent.sh Lines 80-102. Check each result and terminate nonzero on failure.

Also applies to: 11-18, 24-24, 28-28

🤖 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 `@phone-agent.sh` at line 6, Update the audit command invocations in
phone-agent.sh, including the AGENT_START log and the additional veilpiercer
log/verify calls, to check each command’s exit status. Immediately terminate
with a nonzero status when any audit operation fails, ensuring the script cannot
continue or report successful verification after a failure.

Comment thread phone-agent.sh
Comment on lines +8 to +10
while true; do
read -p "You: " msg
if [ "$msg" = "exit" ]; then

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files:\n'
git ls-files | rg '(^|/)phone-agent\.sh$|\.sh$' || true

printf '\nphone-agent.sh outline/size:\n'
wc -l phone-agent.sh
ast-grep outline phone-agent.sh || true

printf '\nRelevant phone-agent.sh contents:\n'
cat -n phone-agent.sh | sed -n '1,140p'

printf '\nSearch for veilpiercer call sites and cleanup:\n'
rg -n "veilpiercer|AGENT_END|cleanup|log|verify|read -p|read -r" phone-agent.sh . || true

Repository: HCF-STUDIOS/openhermit

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Behavioral probe for Bash read with EOF in a while-true loop; no repo code is executed.
printf 'Bash read EOF behavior probe:\n'
{
  i=0
  while true; do
    read -p "You: " msg
    ((i+=1))
    if [ "$msg" = "exit" ]; then
      printf 'exit branch at i=%s msg=%s\n' "$i" "$msg"
      break
    fi
    printf 'loop iteration i=%s msg=%s\n' "$i" "$msg"
    if [ "$i" -gt 8 ]; then
      printf 'breaking after safe upper bound iterations; EOF appears to be handled by loop exit.\n'
      break
    fi
  done
} < /dev/null

Repository: HCF-STUDIOS/openhermit

Length of output: 190


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Locate phone-agent.sh:\n'
git ls-files | grep -E '(^|/)phone-agent\.sh$' || true

printf '\nRelevant phone-agent.sh contents:\n'
if [ -f phone-agent.sh ]; then
  wc -l phone-agent.sh
  cat -n phone-agent.sh | sed -n '1,160p'
fi

printf '\nSearch only phone-agent.sh for read and lifecycle symbols:\n'
if [ -f phone-agent.sh ]; then
  rg -n "read -p|read -r|read|AGENT_END|exit|cleanup|trap|veilpiercer|log|verify" phone-agent.sh || true
fi

Repository: HCF-STUDIOS/openhermit

Length of output: 1893


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Minimal Bash read EOF semantics probe:\n'
tmp="$(mktemp -u)"
cat > "$tmp.sh" <<'BASH'
set -u
i=0
while true; do
  read -p "You: " msg
  ((i+=1))
  printf '%s|read_status=%s|msg="[%s]"|newline_after_prompt_seen=%s\n' "$i" "$?" "$msg" "$?" >&2
  if [ "$msg" = "exit" ]; then
    printf 'exit branch\n'
    break
  fi
  if [ "$i" -ge 5 ]; then
    printf 'break upper bound\n'
    break
  fi
done
BASH
printf 'With empty stdin:\n'
bash "$tmp.sh" < /dev/null
printf '\nUsing IFS= read -r status handling:\n'
bash "$tmp.sh" < "$tmp.sh" || true
rm -f "$tmp.sh" "$tmp" "$tmp"

Repository: HCF-STUDIOS/openhermit

Length of output: 870


🏁 Script executed:

#!/bin/bash
set -euo pipefail

tmp="$(mktemp -u)"
cat > "$tmp" <<'BASH'
#!/bin/bash
set -u
i=0
while true; do
  trap 'printf "caught signal\n"; exit 0' INT TERM
  read -p "You: " msg
  ((i+=1))
  printf '%s|read_status=%s|msg="[%s]"\n' "$i" "$?" "$msg" >&2
  if [ "$msg" = "exit" ]; then
    printf 'exit branch\n'
    break
  fi
  if [ "$i" -ge 5 ]; then
    printf 'break upper bound\n'
    break
  fi
done
BASH

printf 'Bash read with trailing escape newline then EOF:\n'
printf 'abc\\\n' | bash "$tmp"
printf '\nRead-only status probe from bash manual: "read returns false when end of file is reached"\n'
bash -n "$tmp" || true
rm -f "$tmp"

Repository: HCF-STUDIOS/openhermit

Length of output: 446


Handle EOF before logging a closed stdin as a repeated message.

read returns false at EOF, but the loop ignores the status and treats the previous msg value as a new user message on each empty-line iteration, so abrupt stdin closure can repeatedly append USER_MSG events. Route EOF through the normal cleanup path and use IFS= read -r -p "You: " msg to parse the last user input exactly.

🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 9-9: read without -r will mangle backslashes.

(SC2162)

🤖 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 `@phone-agent.sh` around lines 8 - 10, Update the input loop around the read
command to use IFS= read -r -p "You: " msg and check its return status before
processing msg. On EOF, route execution through the existing normal cleanup path
instead of logging or appending another USER_MSG event; preserve the current
exit-command handling for valid input.

Source: Linters/SAST tools

Comment thread phone-agent.sh
Comment on lines +8 to +16
while true; do
read -p "You: " msg
if [ "$msg" = "exit" ]; then
veilpiercer log "AGENT_END" "Session ended - $COUNT messages"
echo ""
echo "✓ Verifying audit trail..."
veilpiercer verify
break
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Add interruption cleanup for audited sessions.

Ctrl-C, SIGTERM, and similar termination paths bypass AGENT_END and veilpiercer verify; only typing exit performs cleanup. Add an idempotent cleanup function registered with trap so interrupted sessions are closed and verification failures are propagated.

🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 9-9: read without -r will mangle backslashes.

(SC2162)

🤖 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 `@phone-agent.sh` around lines 8 - 16, Update the interactive loop around
`AGENT_END` and `veilpiercer verify` by adding an idempotent cleanup function
and registering it with traps for Ctrl-C, SIGTERM, and related termination
signals. Ensure cleanup logs the session end, runs audit verification once, and
preserves or propagates verification failures across both typed `exit` and
interrupted termination paths.

Comment thread phone-agent.sh
Comment on lines +23 to +24
sanitized=$(echo "$msg" | sed 's/"//g' | cut -c1-100)
veilpiercer log "USER_MSG" "[$COUNT] $sanitized"

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 | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files around phone-agent/veilpiercer =="
git ls-files | rg '(^|/)phone-agent\.sh$|veilpiercer|\.veilpiercer|README|privacy|POLIC|SECURITY|config' || true

echo
echo "== phone-agent.sh =="
if [ -f phone-agent.sh ]; then
  cat -n phone-agent.sh
fi

echo
echo "== search for USER_MSG / persisted ledger / redaction =="
rg -n "USER_MSG|\.veilpiercer|veilpiercer|redact|privacy|policy|PII|password|secret|token|credential|truncate|sanitize|sanitized" . --glob '!node_modules' --glob '!dist' --glob '!build' || true

Repository: HCF-STUDIOS/openhermit

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate phone-agent.sh =="
fd -a '^phone-agent\.sh$' . || true

echo
echo "== inspect phone-agent.sh =="
while IFS= read -r -d '' f; do
  echo "--- $f"
  cat -n "$f"
done < <(fd '^phone-agent\.sh$' . -print0)

echo
echo "== targeted USR_MSG and veilpiercer mentions =="
rg -n "USER_MSG|VEIL|veil|veilpiercer|phone|PHONE|\.veilpiercer\.jsonl" run-with-audit.sh start-hermit-audit.sh phone-agent.sh 2>/dev/null || true

Repository: HCF-STUDIOS/openhermit

Length of output: 536


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== phone-agent.sh =="
cat -n phone-agent.sh

echo
echo "== targeted mentions =="
rg -n "USER_MSG|VEIL|veil|veilpiercer|phone|PHONE|\.veilpiercer\.jsonl|redact|privacy|policy" run-with-audit.sh start-hermit-audit.sh phone-agent.sh README.md LICENSE* 2>/dev/null || true

echo
echo "== inspect audit log implementation snippets =="
rg -n "function .*veil|declare -f .*veil|veilpiercer|USER_MSG|\\.veilpiercer" . --glob '*.sh' --max-count 80 || true

Repository: HCF-STUDIOS/openhermit

Length of output: 4706


Do not persist raw phone messages without an explicit privacy policy.

Removing quotes and truncating to 100 characters does not redact sensitive content. USER_MSG writes user-controlled phone messages to the persisted .veilpiercer.jsonl audit ledger; use approved redaction or metadata/digests unless content retention, access controls, and retention limits are explicitly required and documented.

🤖 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 `@phone-agent.sh` around lines 23 - 24, Update the USER_MSG logging in the
message-processing flow to avoid persisting raw phone-message content; replace
the sanitized message payload with the approved redaction, metadata, or digest
mechanism. Do not rely on quote removal or truncation as privacy protection, and
preserve the existing count/context information in veilpiercer log.

Comment thread work-agent.sh
veilpiercer log "WORK_AGENT_START" "Work tracking session started"

while true; do
read -p "Agent> " cmd

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)work-agent\.sh$' || true

for f in $(git ls-files | rg '(^|/)work-agent\.sh$' || true); do
  echo "== outline/stat: $f =="
  wc -l "$f"
  echo "== read usages: $f =="
  rg -n '^\s*read\b|read\s+-' "$f" || true
  echo "== relevant lines: $f =="
  sed -n '1,80p' "$f" | cat -n
done

echo "== bash read behavior probe =="
bash -c 'cmd="x\\\\y"; read -p "cmd? " c; printf "without -r: %q\n" "$c"'
bash -c 'cmd="x\\\\y"; IFS= read -r -p "cmd? " c; printf "with -r: %q\n" "$c"'
bash -c 'task="name\\\\value"; IFS= read -r -p "task? " t; printf %q "$t"; printf "\n"'

Repository: HCF-STUDIOS/openhermit

Length of output: 3414


Preserve literal backslashes in interactive inputs.

read without -r treats \ as an escape character, so command and task-name inputs can be altered before being written to .current_task, work_tasks.csv, and veilpiercer logs. Use IFS= read -r -p ... for both inputs.

🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 14-14: read without -r will mangle backslashes.

(SC2162)

🤖 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 `@work-agent.sh` at line 14, Update both interactive input reads in
work-agent.sh to use IFS= read -r -p, preserving literal backslashes in command
and task-name values before they are written to .current_task, work_tasks.csv,
and veilpiercer logs.

Source: Linters/SAST tools


🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

if [ -f work-agent.sh ]; then
  echo "## file exists"
  wc -l work-agent.sh
  echo "## outline/contents"
  cat -n work-agent.sh | sed -n '1,220p'
  echo "## read uses"
  rg -n "read -p|if|exit|trap|while" work-agent.sh
else
  echo "work-agent.sh not found"; git ls-files | rg 'work-agent\.sh|agent|work'
fi

Repository: HCF-STUDIOS/openhermit

Length of output: 4546


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Behavioral probe for the relevant shell pattern in an isolated subshell.
python3 - <<'PY'
import subprocess, textwrap, shlex

cases = {
    "normal_exit": 'while true; do read -p "Agent> " cmd; echo "CMD<$cmd>"; done',
    "eof_with_stripped_read": 'while true; do read -p "Agent> " cmd || continue; echo " CMD<$cmd>"; done',
    "eof_with_unstripped_read": 'while true; do read -p "Agent> " cmd; echo " CMD<$cmd>"; done',
}

for name, script in cases.items():
    print(f"\n## {name}")
    proc = subprocess.run(["bash", "-c", script], input=b"", stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3)
    print("exit:", proc.returncode)
    print("stdout:", proc.stdout.decode().splitlines()[:10])
    print("stderr:", proc.stderr.decode().splitlines()[:10])

script = r'''
set -e
while true; do
  read -p "Agent> " cmd
  echo "CMD<$cmd>"
done
'''
print("\n## set -e + eof")
proc = subprocess.run(["bash", "-c", script], input=b"", stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3)
print("exit:", proc.returncode)
print("stdout:", proc.stdout.decode().splitlines()[:10])
print("stderr:", proc.stderr.decode().splitlines()[:10])
PY

Repository: HCF-STUDIOS/openhermit

Length of output: 1014


Handle EOF from read -p "Agent> " cmd.

At line 14, read exits the script on Ctrl-D/closed input but the set -eu script does not reach WORK_AGENT_END, final verification, or any cleanup. Detect the failed read and route through the normal session-finalization before exiting.

🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 14-14: read without -r will mangle backslashes.

(SC2162)

🤖 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 `@work-agent.sh` at line 14, Update the command-reading loop around read in the
work-agent script to detect EOF or another failed read, then route through the
existing WORK_AGENT_END/session-finalization path so verification and cleanup
still run before exiting. Preserve normal command handling for successful reads
and ensure the EOF path terminates with the appropriate exit status after
finalization.

Comment thread work-agent.sh
help)
echo ""
echo "Commands:"
echo " time <task> - Start timing a task"

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

Make the documented time <task> command work.

The help text advertises time <task>, but the case only accepts exactly time; time Design review is rejected as unknown. Either parse the argument or document time followed by the prompt.

Also applies to: 29-30

🤖 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 `@work-agent.sh` at line 20, Update the command dispatch case for time so it
accepts the documented task argument, including prompts with spaces, and passes
that task to the timing workflow. Keep the help text and existing behavior for
other commands unchanged.

Comment thread work-agent.sh
Comment on lines +29 to +35
time)
read -p "Task name: " task
START=$(date +%s)
echo "$task" > .current_task
echo "$START" > .task_start_time
veilpiercer log "TASK_STARTED" "$task"
echo "✓ Timing: $task"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not overwrite an active timer.

A second time command replaces .current_task and .task_start_time, losing the first task without a completion event or billable record. Refuse to start until the current task is stopped.

🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 30-30: read without -r will mangle backslashes.

(SC2162)

🤖 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 `@work-agent.sh` around lines 29 - 35, Update the time command handling to
check for an existing active timer before writing .current_task or
.task_start_time. If a timer is active, refuse to start the new task and leave
the existing timer state unchanged; otherwise preserve the current task
initialization, TASK_STARTED logging, and timing output.

Comment thread work-agent.sh
Comment on lines +32 to +33
echo "$task" > .current_task
echo "$START" > .task_start_time

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 | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files matching work-agent =="
fd -a 'work-agent' . || true

echo "== target file excerpt =="
if [ -f work-agent.sh ]; then
  nl -ba work-agent.sh | sed -n '1,120p'
fi

echo "== symlink candidates and current directory behavior =="
python3 - <<'PY'
import os
for p in ('.current_task','.task_start_time','.task_start_time.'):
    print(f"{p}: exists={os.path.lexists(p)} islink={os.path.islink(p)} abs={os.path.abspath(p)}")
PY

Repository: HCF-STUDIOS/openhermit

Length of output: 296


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target file excerpt =="
awk '{printf "%7d\t%s\n", NR, $0}' work-agent.sh | sed -n '1,140p'

echo "== file metadata =="
stat -c '%a %n' work-agent.sh 2>/dev/null || ls -l work-agent.sh

echo "== symlinks and current directory writes for target paths =="
python3 - <<'PY'
import os
for p in ('.current_task','.task_start_time','.task_start_time.'):
    try:
        print(f"{p}: exists={os.path.lexists(p)} islink={os.path.islink(p)} abs={os.path.abspath(p)} inode={os.lstat(p).st_ino if os.path.lexists(p) else None}")
    except FileNotFoundError:
        print(f"{p}: exists=False")
PY

echo "== references to state files in repository =="
grep -RIn '\.current_task\|\.task_start_time' . --exclude-dir=.git 2>/dev/null || true

Repository: HCF-STUDIOS/openhermit

Length of output: 6814


Use a private state directory for work-agent temporary files.

The script writes state-adjacent paths are predictable relative paths, and work_tasks.csvis appended at line 49. If the user runs the script as an executable from an untrusted checkout, these relative writes can overwrite or append to attacker-controlled files. Put the state in a private, permission-restricted directory and derivework_tasks.csv` from an installed canonical location instead of relying on the caller’s CWD.

🤖 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 `@work-agent.sh` around lines 32 - 33, Update work-agent.sh to create and use a
private, permission-restricted state directory for temporary files such as
.current_task and .task_start_time, rather than writing predictable paths in the
caller’s working directory. Also change the work_tasks.csv append logic to
resolve the file from the script’s installed canonical location instead of the
current working directory.

Comment thread work-agent.sh
DURATION=$((END - START))
MINS=$((DURATION / 60))

echo "$TASK,$MINS,$(date)" >> work_tasks.csv

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not parse raw task names as CSV fields.

A task named Client A, 9999 makes awk treat 9999 as its duration, corrupting the invoice total. Use an unambiguous internal format (for example, TSV with validation) or a CSV-aware serializer/parser.

Also applies to: 72-72

🤖 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 `@work-agent.sh` at line 49, Update the task persistence and parsing around the
work_tasks.csv append and the awk processing near line 72 so task names
containing commas cannot shift the duration field. Use a CSV-aware
serializer/parser or replace the internal format with a validated unambiguous
delimiter, and ensure invoice totals continue reading the actual MINS value.

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