ocas-mentor
Mentor orchestrates and evaluates multi-skill workflows, proposing improvements based on performance analysis and project management.
Install this skill
or
59/100
Security score
The ocas-mentor skill was audited on Sep 25, 2026 and we found 5 security issues across 3 threat categories, including 2 high-severity. Review the findings below before installing.
Categories Tested
Security Issues
medium line 93
Command substitution pattern
SourceSKILL.md
| 91 | **`execute_code` is blocked in cron-triggered jobs.** All heartbeat, update, and plan runs triggered by cron must use `terminal()` with inline `python3 /path/to/scripts.py` for multi-stage logic. **CRITICAL: Do NOT use `<<` heredoc syntax in `terminal()`** — the `<<` delimiter triggers the terminal's foreground-background detection, causing exit_code=-1. Write scripts to `/tmp/` via `write_file` first, then invoke with `python3 /tmp/script.py`. See gotcha #70. |
| 92 | |
| 93 | **Pipe-to-python bash quoting pitfall (confirmed 2026-06-29 dispatch):** The pattern `VAR=$(tail -1 "$file" | python3 -c "..."))` fails with `syntax error near unexpected token` because bash's command substitution `$(...)` with a pipe and double quotes creates parsing conflicts. **Fix:** Use single quotes inside the Python script and ensure the pipe is inside the `$()`: `VAR=$(tail -1 "$file" | python3 -c 'import sys,json; print(json.loads(sys.stdin.read()).get("field",""))' ))` — note the single quotes. Or safer: avoid inline pipe-to-python entirely; write a `/tmp/script.py` via `write_file` and pipe into it: `tail -1 <fs-root>/file.jsonl | python3 /tmp/extract_field.py`. The shell then has no embedded Python to misparse. |
| 94 | |
| 95 | **`execute_code` blocking applies to ALL cron-triggered jobs** (confirmed 2026-06-25 dispatch #99). This includes not just heartbeat scripts but also state file writes, JSON manipulation, and any multi-step Python logic. When the dispatch caller (triggered by cron) needs to write JSON state files or perform set-difference syncs, it MUST use `terminal()` with `cat > file << 'EOF'` for JSON files or `echo >> file` for JSONL appends — never `execute_code`. Attempting `execute_code` in cron produces: `BLOCKED: execute_code runs arbitrary local Python`. This is a hard runtime constraint, not a suggestion. |
medium line 106
Command substitution pattern
SourceSKILL.md
| 104 | **Inline Python variable scoping in `terminal()`** — When composing multi-step Python logic inline in `terminal()` (either as heredoc or `python3 -c`), variables defined inside a function are NOT available in the outer scope. This manifests as `NameError: name 'X' is not defined` at a line that logically follows the definition. **Fix:** Structure inline scripts so all logic is in a single flat scope (no nested functions), or write the script to `/tmp/` via `write_file` where you can verify scoping independently. Confirmed 2026-06-24 dispatch: `skill = jid.split("/")[0]` inside `extract_signals()` was invisible to the caller's loop. |
| 105 | |
| 106 | **Sandbox file discovery failure:** In the cron sandbox, Python's `subprocess.run(["find", ...])` and `os.walk()` silently return 0 results even when the filesystem is fully accessible via shell tools. Use the shell-pipe pattern: `find JOURNALS_DIR -name "*.json" -mtime -3 | sort -u > /tmp/mentor_files_3d.txt && python3 scripts/cron-heartbeat-light.py < /tmp/mentor_files_3d.txt`. **CRITICAL:** Any pipe to python3 (e.g., `cmd | python3 -c "..."`, `VAR=$(cmd | python3 -c "...")`, or `cat file | python3`) is blocked by the `tirith:pipe_to_interpreter` security rule in cron mode. Always avoid piping to python3; use alternatives like temporary files (`cmd > /tmp/out && python3 -c "..." < /tmp/out`), here-strings (`python3 -c "..." <<< "$(cmd)"`), or temporary scripts. See `references/shell-write-pattern.md`. |
| 107 | |
| 108 | **Pipe-to-interpreter blocks the ENTIRE terminal() call (confirmed 2026-07-08):** A trailing `tail -1 file | python3 -c "..."` verification step at the end of a multi-step cron `terminal()` command causes the security scanner to reject the WHOLE command — not just the pipe. Observed signature: `exit_code=-1`, `status: pending_approval`, `pattern_key: tirith:pipe_to_interpreter`. ALL steps in that call are lost (pre-run counts, script run, verification) and must be re-run. The block fires on the presence of `| python3` ANYWHERE in the command string, regardless of position. FIX: never put `cmd | python3` inside a cron `terminal()` call, even for final field checks. Do field verification via the `read_file` tool (outside terminal) or a `/tmp/*.py` script invoked WITHOUT a pipe (`python3 /tmp/check.py`). |
low line 200
Command substitution pattern
SourceSKILL.md
| 198 | **Cron dispatch verification shortcut (confirmed 2026-06-25):** After a cron-triggered dispatch completes all pipelines, a single-line verification confirms state: |
| 199 | ```bash |
| 200 | echo "Forge: $(ls .../ocas-forge/2026-06-25/ | tail -2)" && echo "Mentor: evidence=$(wc -l < .../mentor/evidence.jsonl) ingestion=$(wc -l < .../mentor/ingestion_log.jsonl)" && echo "Praxis: eval=$(wc -l < .../journals_evaluated.jsonl)" |
| 201 | ``` |
| 202 |
high line 273
Urgency-based manipulation
SourceSKILL.md
| 271 | Check both sources before running Praxis ingest. If found, mark as `already_ingested` in evidence and skip silently. This is NOT a second-wave false positive — the journal was genuinely new but already processed by a sibling pipeline. |
| 272 | |
| 273 | **CRITICAL: Mentor heartbeat updates Praxis ingest state** — The `cron-heartbeat-light.py` script updates `ingest_state.json:last_ingest_run` when it writes evidence. If Praxis dispatch runs immediately after in the same multi-skill dispatch, its mtime-based journal discovery may find 0 new journals because the state timestamp moved forward. The dispatcher must capture `last_ingest_run` BEFORE running Mentor and pass it to Praxis. See Praxis SKILL.md § Dispatch / Cron Integration step 3. |
| 274 | |
| 275 | **Caveat — heartbeat does NOT reliably advance Praxis ingest state (verified 2026-07-11):** In a multi-skill dispatch, after running `cron-heartbeat-light.py` via `python3 script.py < filelist` (returncode 0, heartbeat journal written to disk), `ingest_state.json:last_ingest_run` at `<hermes-home>/profiles/indigo/commons/data/ocas-praxis/` was UNCHANGED — it still held the prior-wave value. The dispatch caller MUST explicitly advance `last_ingest_run` itself after the heartbeat (and sync `journals_evaluated_count` / `last_eval_file_line` to the actual eval-file `wc -l`). Do NOT assume the script moved the state forward. A stale `last_ingest_run` is usually harmless (grep-based per-file classification wins over mtime discovery), but it means the state no longer reflects this wave's work and any later step that trusts it will read the prior-wave timestamp. |
high line 106
Temp file execution
SourceSKILL.md
| 104 | **Inline Python variable scoping in `terminal()`** — When composing multi-step Python logic inline in `terminal()` (either as heredoc or `python3 -c`), variables defined inside a function are NOT available in the outer scope. This manifests as `NameError: name 'X' is not defined` at a line that logically follows the definition. **Fix:** Structure inline scripts so all logic is in a single flat scope (no nested functions), or write the script to `/tmp/` via `write_file` where you can verify scoping independently. Confirmed 2026-06-24 dispatch: `skill = jid.split("/")[0]` inside `extract_signals()` was invisible to the caller's loop. |
| 105 | |
| 106 | **Sandbox file discovery failure:** In the cron sandbox, Python's `subprocess.run(["find", ...])` and `os.walk()` silently return 0 results even when the filesystem is fully accessible via shell tools. Use the shell-pipe pattern: `find JOURNALS_DIR -name "*.json" -mtime -3 | sort -u > /tmp/mentor_files_3d.txt && python3 scripts/cron-heartbeat-light.py < /tmp/mentor_files_3d.txt`. **CRITICAL:** Any pipe to python3 (e.g., `cmd | python3 -c "..."`, `VAR=$(cmd | python3 -c "...")`, or `cat file | python3`) is blocked by the `tirith:pipe_to_interpreter` security rule in cron mode. Always avoid piping to python3; use alternatives like temporary files (`cmd > /tmp/out && python3 -c "..." < /tmp/out`), here-strings (`python3 -c "..." <<< "$(cmd)"`), or temporary scripts. See `references/shell-write-pattern.md`. |
| 107 | |
| 108 | **Pipe-to-interpreter blocks the ENTIRE terminal() call (confirmed 2026-07-08):** A trailing `tail -1 file | python3 -c "..."` verification step at the end of a multi-step cron `terminal()` command causes the security scanner to reject the WHOLE command — not just the pipe. Observed signature: `exit_code=-1`, `status: pending_approval`, `pattern_key: tirith:pipe_to_interpreter`. ALL steps in that call are lost (pre-run counts, script run, verification) and must be re-run. The block fires on the presence of `| python3` ANYWHERE in the command string, regardless of position. FIX: never put `cmd | python3` inside a cron `terminal()` call, even for final field checks. Do field verification via the `read_file` tool (outside terminal) or a `/tmp/*.py` script invoked WITHOUT a pipe (`python3 /tmp/check.py`). |
Scanned on Sep 25, 2026
View Security DashboardGitHub Stars 1
Rating
5.01
Rate this skill
Categoryproject management
UpdatedSeptember 26, 2026
hermesfrontenddocxgitapitestingbackendproject-manageroperations-managergrowth-pmbusiness-process-analystdata-analystgithubproject managementoperationsproductdata analytics
indigokarasu/mentor