Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
29a528f
Add methodology analysis phase for RLCR loop exit
SihaoLiu Mar 13, 2026
d3ded24
Fix methodology analysis completion: require report and fail closed
SihaoLiu Mar 13, 2026
7282f6e
Fix read validator to allow historical round access during methodolog…
SihaoLiu Mar 13, 2026
50e8bbb
Harden methodology analysis read bypass with path canonicalization an…
SihaoLiu Mar 13, 2026
f34d45f
Enforce read-only project files during methodology analysis phase
SihaoLiu Mar 13, 2026
87687a2
Fix spawned agent bypass and broaden bash restriction coverage
SihaoLiu Mar 13, 2026
9888044
Fix realpath for non-existent files and narrow gh allowlist
SihaoLiu Mar 13, 2026
4c48209
Block project-root reads and interpreters during methodology analysis
SihaoLiu Mar 13, 2026
786ed32
Block shell entry points and fix concurrent session binding in method…
SihaoLiu Mar 13, 2026
f2a12c6
Allow cancel script during methodology analysis, remove gh issue earl…
SihaoLiu Mar 13, 2026
7b91c47
Scope methodology fallback to spawned agents only, add missing git su…
SihaoLiu Mar 13, 2026
3c85332
Remove cross-session methodology fallback, add realpath raw path fall…
SihaoLiu Mar 13, 2026
5c123c2
Expand methodology bash blocklist, require non-empty report, fix moni…
SihaoLiu Mar 13, 2026
03ac7d0
Tighten cancel allowlist, document spawned agent limitation, remove d…
SihaoLiu Mar 13, 2026
5a08329
Remove raw records from read allowlist, document bash read limitation
SihaoLiu Mar 13, 2026
2cba950
Fix stale error messages in read validator methodology analysis block
SihaoLiu Mar 13, 2026
3eed7d6
Add missing template for methodology analysis state file block message
SihaoLiu Mar 13, 2026
0edbe3f
Merge dev: resolve conflicts with yolo/skip-quiz flags
SihaoLiu Mar 13, 2026
13a47fb
Fix cancel allowlist regex and move methodology handler before git-clean
SihaoLiu Mar 13, 2026
9b961a8
Harden RLCR against mainline drift
tastynoob Mar 15, 2026
cfc46d6
Use portable shebang across all shell scripts
Emin017 Mar 17, 2026
4303249
Bump version to 1.14.1 for branch CI validation
Emin017 Mar 17, 2026
4deb1db
Harden template-loader error handling and reduce code duplication
zevorn Mar 18, 2026
0844648
Add native Codex hook support and harden install/test flows
shinezyy Mar 15, 2026
dbb88bc
fixed tests for bitlesson-select-routing
shinezyy Mar 26, 2026
9ed3e1a
bump version of humanize
SihaoLiu Mar 28, 2026
03e159c
Merge PR #49: Use portable shebang across all shell scripts
SihaoLiu Mar 28, 2026
1862329
Merge PR #50: Harden template-loader error handling and reduce duplic…
SihaoLiu Mar 28, 2026
fe1832d
Merge PR #42: Add methodology analysis for RLCR loop exit
SihaoLiu Mar 28, 2026
a8f85e8
Merge PR #48: Harden RLCR against mainline drift
SihaoLiu Mar 28, 2026
611a437
Fix codex_hooks flag probe, managed-hook regex, and legacy compat
SihaoLiu Mar 29, 2026
2a0faf6
Fix BSD sed portability, awk field splitting, and strict parser defaults
SihaoLiu Mar 29, 2026
d122c82
Fix path injection in shim generation, JSON escaping, and legacy trac…
SihaoLiu Mar 29, 2026
9cf2544
Merge branch 'main' into dev
SihaoLiu Mar 29, 2026
febbc00
Fix relative path bypass in methodology analysis read guard
SihaoLiu Mar 29, 2026
17fabf7
Revert version back to 1.16.0 on dev branch
SihaoLiu Mar 29, 2026
2ab5361
Fix relative path bypass in write validator and add Codex flag probes…
SihaoLiu Mar 29, 2026
4326860
Fix mainline verdict parser picking last keyword instead of first
SihaoLiu Mar 29, 2026
016caca
Add ask-gemini skill and tool-filtered monitor subcommands
SihaoLiu Mar 29, 2026
883e3f5
Revert version back to 1.16.0 to match dev branch
SihaoLiu Mar 29, 2026
916fc50
Reject path traversal segments in methodology analysis fallback guards
SihaoLiu Mar 29, 2026
515f90a
Merge pull request #52 from humania-org/ask-gemini
SihaoLiu Mar 29, 2026
95a6b7b
Fix edit validator path fallback and reject whitespace-only completio…
SihaoLiu Mar 29, 2026
bd506f2
Reject ambiguous multi-keyword verdict lines and fix Gemini CLI insta…
SihaoLiu Mar 29, 2026
4561bc4
Shell-quote hook command paths and reject ambiguous verdict lines
SihaoLiu Mar 29, 2026
338b4dd
Remove PR loop feature entirely
SihaoLiu Mar 29, 2026
3374acb
fix minor display bug of monitor script
SihaoLiu Mar 29, 2026
a1f3614
Be more specific about what is a round
SihaoLiu Mar 29, 2026
c045dff
fix: normalize path slashes in PostToolUse hook to prevent session_id…
gyy0592 Apr 4, 2026
707097c
revert: remove version bump, keep only hook fix
gyy0592 Apr 4, 2026
79714b7
Add support for multiple comment formats in refine-plan
Lyken17 Apr 9, 2026
228d6aa
Update README.md
Lyken17 Apr 13, 2026
28813b6
Merge pull request #68 from gyy0592/fix/session-id-double-slash
SihaoLiu Apr 13, 2026
690fb27
fix: use pipe delimiter in find_comment_markers to avoid splitting CM…
SihaoLiu Apr 13, 2026
027bf0b
fix: update test assertions to match renamed comment terminology
SihaoLiu Apr 13, 2026
3bef3ef
Merge pull request #78 from Lyken17/main
SihaoLiu Apr 13, 2026
722eb25
[docs] clarify the place to use monitor script
SihaoLiu Apr 13, 2026
e61b570
Merge branch 'main' into dev
SihaoLiu Apr 14, 2026
7c4356c
fix: correct managed-hook dedup regex and block unresolvable symlinks
SihaoLiu Apr 14, 2026
c4389bb
feat: add integral context to RLCR review prompts (PID complete)
zevorn Apr 14, 2026
50ed1bc
Merge pull request #81 from zevorn/feat/rlcr-integral-context
SihaoLiu Apr 15, 2026
fc8a027
Update repo org URLs from humania-org to PolyArch
SihaoLiu Apr 15, 2026
5c2f07f
Update remaining repo org URLs from humania-org to PolyArch
SihaoLiu Apr 15, 2026
41a02e8
Merge branch 'main' into dev
SihaoLiu Apr 15, 2026
84ebaee
Merge branch 'main' into dev and bump version to 1.16.1
SihaoLiu Apr 15, 2026
67fa1ae
Reset dev version to 1.16.0
SihaoLiu Apr 15, 2026
a9078aa
fix: block tracked humanize loop state from git
xyyy1420 Apr 16, 2026
421ae97
Narrow tracked-humanize guard to .humanize/ to avoid false blocks
SihaoLiu Apr 16, 2026
0f025cb
Merge pull request #86 from xyyy1420/dev
SihaoLiu Apr 16, 2026
9730744
Allow natural stop when background tasks still running
SihaoLiu Apr 16, 2026
3adf8ef
Expand '~' in transcript_path before background-task file check
SihaoLiu Apr 16, 2026
38691dd
Make tilde-path regressions portable and cover the wrapper too
SihaoLiu Apr 16, 2026
6a1d931
Prevent RLCR loop orphaning when session dies mid-background
SihaoLiu Apr 16, 2026
69587a7
Prefer own-session match and clean marker on resume
SihaoLiu Apr 16, 2026
0535919
Recognise SDK task_notification completions and keep recovery marker
SihaoLiu Apr 16, 2026
60e2635
Narrow cross-session adoption and block foreign-session hijack
SihaoLiu Apr 16, 2026
7fb3038
Tighten cross-session guard and marker cleanup
SihaoLiu Apr 16, 2026
7538f74
Silence ambiguous callers and scope transcript scan to this loop
SihaoLiu Apr 16, 2026
9c80698
Normalize loop-start boundary into actual UTC
SihaoLiu Apr 16, 2026
74671f7
Pin rlcr-stop-gate project root at every wrapper testsite
SihaoLiu Apr 16, 2026
39f09c4
Avoid duplicate jq pass in bg-pending short-circuit
SihaoLiu Apr 16, 2026
3711e5f
Extract bg-task helpers into dedicated lib and guard transcript_path …
SihaoLiu Apr 16, 2026
b955a69
Merge pull request #91 from PolyArch/do-not-block-stop-when-backgroun…
SihaoLiu Apr 17, 2026
fdd8670
Add liveness probe to prune orphaned background task IDs
SihaoLiu Apr 17, 2026
850a444
WIP: wrap all path with realpath
SihaoLiu Apr 17, 2026
3dcb4dd
Canonicalize both sides of cancel-authorization path comparison
SihaoLiu Apr 17, 2026
0e2c6a0
Merge pull request #93 from PolyArch/use-realpath4everything
SihaoLiu Apr 17, 2026
b10fbf1
Reject symlink aliases for cancel source and destination
SihaoLiu Apr 17, 2026
cf17140
Use prefix-only canonicalization in read/write path validators
SihaoLiu Apr 17, 2026
98d86c0
Merge pull request #94 from PolyArch/use-realpath4everything
SihaoLiu Apr 17, 2026
68bde28
Tighten cancel-rlcr-loop allowlist regex in methodology phase
SihaoLiu Apr 17, 2026
47ee97d
Reject unresolvable symlinks in methodology write/edit validators
SihaoLiu Apr 17, 2026
a4fbccd
Remove version bump hint from CLAUDE.md
SihaoLiu Apr 17, 2026
22e52bd
Wire test-disable-nested-codex-hooks into run-all-tests
SihaoLiu Apr 17, 2026
0ca864d
Place --disable codex_hooks after the Codex subcommand
SihaoLiu Apr 17, 2026
cd367ee
Reject shell metacharacters in cancel allowlist exception
SihaoLiu Apr 17, 2026
d09a282
Block patch in methodology-phase Bash denylist
SihaoLiu Apr 17, 2026
5990827
Gate methodology completion on a clean git tree
SihaoLiu Apr 17, 2026
3a0cd7c
docs: add gen-idea design spec for directed-swarm idea drafting
shinan6 Apr 20, 2026
84ffc93
docs: add gen-idea implementation plan
shinan6 Apr 20, 2026
e18d013
feat(gen-idea): add draft template for directed-swarm output
shinan6 Apr 20, 2026
e3e38de
feat(gen-idea): add IO validation script with slug resolution
shinan6 Apr 20, 2026
911c5da
docs(plan): align Task 2 script with implemented fixes
shinan6 Apr 20, 2026
7e6442b
fix(gen-idea): harden realpath fallback and document tempfile contract
shinan6 Apr 20, 2026
a49ed09
feat(gen-idea): add slash-command spec for directed-swarm drafting
shinan6 Apr 20, 2026
2269e0a
fix(gen-idea): clarify command spec ambiguities surfaced in review
shinan6 Apr 20, 2026
c6d8d19
feat(gen-idea): document command in README, bump to 1.16.1
shinan6 Apr 20, 2026
1adeca4
feat(gen-idea): emit short-idea warning and clarify SLUG usage
shinan6 Apr 20, 2026
695766a
chore: revert version to 1.16.0
SihaoLiu Apr 20, 2026
ad9fe53
remove superpowers docs from branch
SihaoLiu Apr 20, 2026
0e6a5b3
fix(gen-idea): treat whitespace-containing .md args as inline
SihaoLiu Apr 20, 2026
04116b9
fix(gen-idea): reject unreadable markdown input files
SihaoLiu Apr 20, 2026
3e891f3
fix(gen-idea): emit inline idea body via stdout sentinel
SihaoLiu Apr 21, 2026
179a87c
Merge pull request #99 from shinan6/add-gen-idea-command
SihaoLiu Apr 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ temp

# Humanize state directories (runtime-generated, project-local)
.humanize/
.claude-flow/
.swarm/

# Python cache
__pycache__/
Expand Down
23 changes: 23 additions & 0 deletions config/codex-hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"description": "Humanize Codex Hooks - Native Stop hooks for RLCR and PR loops",
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "{{HUMANIZE_RUNTIME_ROOT}}/hooks/loop-codex-stop-hook.sh",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Quote hook command paths before writing hooks.json

The template emits the hook command as a bare path, so when {{HUMANIZE_RUNTIME_ROOT}} contains spaces (for example a custom CODEX_HOME path like /Users/John Doe/.codex), the command is split at runtime and Codex cannot execute the stop hook script. That breaks RLCR/PR exit gating in those installations; the command value should be shell-quoted or otherwise encoded as a single executable path.

Useful? React with 👍 / 👎.

"timeout": 7200,
"statusMessage": "humanize RLCR stop hook"
},
{
"type": "command",
"command": "{{HUMANIZE_RUNTIME_ROOT}}/hooks/pr-loop-stop-hook.sh",
"timeout": 7200,
"statusMessage": "humanize PR stop hook"
}
]
}
]
}
}
4 changes: 4 additions & 0 deletions docs/bitlesson.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Provider routing is automatic:

If the configured provider binary is missing, the selector falls back to the default Codex model so the loop can still proceed.

On Codex-only installs, Humanize writes `provider_mode: "codex-only"` into the user config.
When that mode is present, the selector forces BitLesson selection onto the Codex/OpenAI path
before provider resolution, even if an older default such as `haiku` would otherwise route to Claude.

## Workflow

Each project keeps its BitLesson knowledge base at `.humanize/bitlesson.md`.
Expand Down
33 changes: 32 additions & 1 deletion docs/install-for-codex.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Install Humanize Skills for Codex

This guide explains how to install the Humanize skills for Codex skill runtime (`$CODEX_HOME/skills`).
This guide explains how to install Humanize for Codex CLI, including the skill runtime (`$CODEX_HOME/skills`) and the native Codex `Stop` hook (`$CODEX_HOME/hooks.json`).

## Quick Install (Recommended)

Expand All @@ -25,8 +25,14 @@ Or use the unified installer directly:
This will:
- Sync `humanize`, `humanize-gen-plan`, `humanize-refine-plan`, and `humanize-rlcr` into `${CODEX_HOME:-~/.codex}/skills`
- Copy runtime dependencies into `${CODEX_HOME:-~/.codex}/skills/humanize`
- Install/update native Humanize Stop hooks in `${CODEX_HOME:-~/.codex}/hooks.json`
- Enable the experimental `codex_hooks` feature in `${CODEX_HOME:-~/.codex}/config.toml` when `codex` is available
- Seed `~/.config/humanize/config.json` with a Codex/OpenAI `bitlesson_model` when that key is not already set
- Mark the install as `provider_mode: "codex-only"` when using `--target codex`
- Use RLCR defaults: `codex exec` with `gpt-5.4:high`, `codex review` with `gpt-5.4:high`

Requires Codex CLI `0.114.0` or newer for native hooks. Older Codex builds are not supported by the Codex install path.

## Verify

```bash
Expand Down Expand Up @@ -58,6 +64,21 @@ Installed files/directories:
- `${CODEX_HOME:-~/.codex}/skills/humanize/templates/`
- `${CODEX_HOME:-~/.codex}/skills/humanize/config/`
- `${CODEX_HOME:-~/.codex}/skills/humanize/agents/`
- `${CODEX_HOME:-~/.codex}/hooks.json`
- `${XDG_CONFIG_HOME:-~/.config}/humanize/config.json` (created or updated only when Humanize config keys are unset)

Verify native hooks:

```bash
codex features list | rg codex_hooks
sed -n '1,220p' "${CODEX_HOME:-$HOME/.codex}/hooks.json"
```

Expected:
- `codex_hooks` is `true`
- `hooks.json` contains `loop-codex-stop-hook.sh` and `pr-loop-stop-hook.sh`
- `${XDG_CONFIG_HOME:-~/.config}/humanize/config.json` contains `bitlesson_model` set to a Codex/OpenAI model such as `gpt-5.4`
- for `--target codex`, `${XDG_CONFIG_HOME:-~/.config}/humanize/config.json` also contains `provider_mode: "codex-only"`

## Optional: Install for Both Codex and Kimi

Expand All @@ -73,6 +94,9 @@ Installed files/directories:

# Custom Codex skills dir
./scripts/install-skills-codex.sh --codex-skills-dir /custom/codex/skills

# Reinstall only the native hooks/config
./scripts/install-codex-hooks.sh
```

## Troubleshooting
Expand All @@ -82,3 +106,10 @@ If scripts are not found from installed skills:
```bash
ls -la "${CODEX_HOME:-$HOME/.codex}/skills/humanize/scripts"
```

If native exit gating does not trigger:

```bash
codex features enable codex_hooks
sed -n '1,220p' "${CODEX_HOME:-$HOME/.codex}/hooks.json"
```
5 changes: 5 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ Current built-in keys:
| `codex_model` | `gpt-5.4` | Shared default model for Codex-backed review and analysis |
| `codex_effort` | `high` | Shared default reasoning effort (`xhigh`, `high`, `medium`, `low`) |
| `bitlesson_model` | `haiku` | Model used by the BitLesson selector agent |
| `provider_mode` | unset | Optional runtime mode hint such as `codex-only` |
| `agent_teams` | `false` | Project-level default for agent teams workflow |
| `alternative_plan_language` | `""` | Optional translated plan variant language; supported values include `Chinese`, `Korean`, `Japanese`, `Spanish`, `French`, `German`, `Portuguese`, `Russian`, `Arabic`, or ISO codes like `zh` |
| `gen_plan_mode` | `discussion` | Default plan-generation mode |
Expand All @@ -300,6 +301,10 @@ To override, add to `.humanize/config.json`:
}
```

On Codex installs, Humanize also seeds `${XDG_CONFIG_HOME:-~/.config}/humanize/config.json`
with a Codex/OpenAI `bitlesson_model` and `provider_mode: "codex-only"` when those keys
are unset, so BitLesson selection stays on the Codex/OpenAI path without probing Claude.

Codex model is resolved with this precedence:
1. CLI `--codex-model` flag (highest priority)
2. Feature-specific defaults (e.g., PR loop defaults to `medium` effort)
Expand Down
11 changes: 7 additions & 4 deletions hooks/loop-codex-stop-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,9 @@ mkdir -p "$CACHE_DIR"

# portable-timeout.sh already sourced above

# Disable native hooks for nested Codex reviewer calls to prevent Stop-hook recursion.
CODEX_DISABLE_HOOKS_ARGS=(--disable codex_hooks)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Guard codex_hooks disable flag behind feature support

This new flag is unconditionally added to nested Codex invocations, but the hook only validates that codex exists and never checks whether the installed CLI supports --disable codex_hooks; on older Codex builds, the nested codex call exits with an unknown-argument error, which causes RLCR stop handling to treat review as failed and repeatedly block loop/finalize exits. Add a feature/version probe (or a fallback path without this flag) before injecting it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@shinezyy can you take a look


# Build command arguments for summary review (codex exec)
CODEX_EXEC_ARGS=("-m" "$CODEX_EXEC_MODEL")
if [[ -n "$CODEX_EXEC_EFFORT" ]]; then
Expand Down Expand Up @@ -1056,14 +1059,14 @@ Provider: codex
echo "# Review base ($review_base_type): $review_base"
echo "# Timeout: $CODEX_TIMEOUT seconds"
echo ""
echo "codex review --base $review_base ${CODEX_REVIEW_ARGS[*]}"
echo "codex ${CODEX_DISABLE_HOOKS_ARGS[*]} review --base $review_base ${CODEX_REVIEW_ARGS[*]}"
} > "$CODEX_REVIEW_CMD_FILE"

echo "Code review command saved to: $CODEX_REVIEW_CMD_FILE" >&2
echo "Running codex review with timeout ${CODEX_TIMEOUT}s in $PROJECT_ROOT (base: $review_base)..." >&2

CODEX_REVIEW_EXIT_CODE=0
(cd "$PROJECT_ROOT" && run_with_timeout "$CODEX_TIMEOUT" codex review --base "$review_base" "${CODEX_REVIEW_ARGS[@]}") \
(cd "$PROJECT_ROOT" && run_with_timeout "$CODEX_TIMEOUT" codex "${CODEX_DISABLE_HOOKS_ARGS[@]}" review --base "$review_base" "${CODEX_REVIEW_ARGS[@]}") \
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Place --disable after Codex subcommands

loop-codex-stop-hook.sh builds nested Codex invocations as codex --disable codex_hooks review ... / codex --disable codex_hooks exec ..., but Codex CLI docs state global flags for subcommands must be placed after the subcommand ("place global flags after it ... so Codex applies them as intended"). In this form, the disable flag may not take effect, which can re-enable hooks during nested reviewer calls and reintroduce Stop-hook recursion/looping under RLCR.

Useful? React with 👍 / 👎.

> "$CODEX_REVIEW_LOG_FILE" 2>&1 || CODEX_REVIEW_EXIT_CODE=$?

echo "Code review exit code: $CODEX_REVIEW_EXIT_CODE" >&2
Expand Down Expand Up @@ -1387,7 +1390,7 @@ CODEX_PROMPT_CONTENT=$(cat "$REVIEW_PROMPT_FILE")
echo "# Working directory: $PROJECT_ROOT"
echo "# Timeout: $CODEX_TIMEOUT seconds"
echo ""
echo "codex exec ${CODEX_EXEC_ARGS[*]} \"<prompt>\""
echo "codex ${CODEX_DISABLE_HOOKS_ARGS[*]} exec ${CODEX_EXEC_ARGS[*]} \"<prompt>\""
echo ""
echo "# Prompt content:"
echo "$CODEX_PROMPT_CONTENT"
Expand All @@ -1397,7 +1400,7 @@ echo "Codex command saved to: $CODEX_CMD_FILE" >&2
echo "Running summary review with timeout ${CODEX_TIMEOUT}s..." >&2

CODEX_EXIT_CODE=0
printf '%s' "$CODEX_PROMPT_CONTENT" | run_with_timeout "$CODEX_TIMEOUT" codex exec "${CODEX_EXEC_ARGS[@]}" - \
printf '%s' "$CODEX_PROMPT_CONTENT" | run_with_timeout "$CODEX_TIMEOUT" codex "${CODEX_DISABLE_HOOKS_ARGS[@]}" exec "${CODEX_EXEC_ARGS[@]}" - \
> "$CODEX_STDOUT_FILE" 2> "$CODEX_STDERR_FILE" || CODEX_EXIT_CODE=$?

echo "Codex exit code: $CODEX_EXIT_CODE" >&2
Expand Down
5 changes: 4 additions & 1 deletion hooks/pr-loop-stop-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1334,12 +1334,15 @@ if [[ "${HUMANIZE_CODEX_BYPASS_SANDBOX:-}" == "true" ]] || [[ "${HUMANIZE_CODEX_
CODEX_AUTO_FLAG="--dangerously-bypass-approvals-and-sandbox"
fi

# Disable native hooks for nested Codex reviewer calls to prevent Stop-hook recursion.
CODEX_DISABLE_HOOKS_ARGS=(--disable codex_hooks)

CODEX_ARGS+=("$CODEX_AUTO_FLAG" "-C" "$PROJECT_ROOT")

CODEX_PROMPT_CONTENT=$(cat "$CODEX_PROMPT_FILE")
CODEX_EXIT_CODE=0

printf '%s' "$CODEX_PROMPT_CONTENT" | run_with_timeout "$PR_CODEX_TIMEOUT" codex exec "${CODEX_ARGS[@]}" - \
printf '%s' "$CODEX_PROMPT_CONTENT" | run_with_timeout "$PR_CODEX_TIMEOUT" codex "${CODEX_DISABLE_HOOKS_ARGS[@]}" exec "${CODEX_ARGS[@]}" - \
> "$CHECK_FILE" 2>/dev/null || CODEX_EXIT_CODE=$?

if [[ $CODEX_EXIT_CODE -ne 0 ]]; then
Expand Down
77 changes: 54 additions & 23 deletions scripts/bitlesson-select.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null
MERGED_CONFIG="$(load_merged_config "$PLUGIN_ROOT" "$PROJECT_ROOT")"
BITLESSON_MODEL="$(get_config_value "$MERGED_CONFIG" "bitlesson_model")"
BITLESSON_MODEL="${BITLESSON_MODEL:-haiku}"
CODEX_FALLBACK_MODEL="$(get_config_value "$MERGED_CONFIG" "codex_model")"
CODEX_FALLBACK_MODEL="${CODEX_FALLBACK_MODEL:-$DEFAULT_CODEX_MODEL}"
PROVIDER_MODE="$(get_config_value "$MERGED_CONFIG" "provider_mode")"
PROVIDER_MODE="${PROVIDER_MODE:-auto}"

# Source portable timeout wrapper
source "$SCRIPT_DIR/portable-timeout.sh"
Expand Down Expand Up @@ -82,12 +86,34 @@ if [[ -z "$BITLESSON_FILE" ]]; then
exit 1
fi

if [[ ! -f "$BITLESSON_FILE" ]]; then
echo "Error: BitLesson file not found: $BITLESSON_FILE" >&2
exit 1
fi

BITLESSON_CONTENT="$(cat "$BITLESSON_FILE")"
if [[ -z "$(printf '%s' "$BITLESSON_CONTENT" | tr -d ' \t\n\r')" ]]; then
echo "Error: BitLesson file is empty (whitespace only): $BITLESSON_FILE" >&2
exit 1
fi

if ! printf '%s\n' "$BITLESSON_CONTENT" | grep -Eq '^[[:space:]]*##[[:space:]]+Lesson:'; then
printf 'LESSON_IDS: NONE\n'
printf 'RATIONALE: The BitLesson file has no recorded lessons yet.\n'
exit 0
fi

# ========================================
# Determine Provider from BITLESSON_MODEL
# ========================================

BITLESSON_PROVIDER="$(detect_provider "$BITLESSON_MODEL")"

if [[ "$PROVIDER_MODE" == "codex-only" ]] && [[ "$BITLESSON_PROVIDER" == "claude" ]]; then
BITLESSON_MODEL="$CODEX_FALLBACK_MODEL"
BITLESSON_PROVIDER="codex"
fi

# ========================================
# Conditional Dependency Check (with fallback)
# ========================================
Expand All @@ -99,17 +125,6 @@ if ! check_provider_dependency "$BITLESSON_PROVIDER" 2>/dev/null; then
check_provider_dependency "$BITLESSON_PROVIDER"
fi

if [[ ! -f "$BITLESSON_FILE" ]]; then
echo "Error: BitLesson file not found: $BITLESSON_FILE" >&2
exit 1
fi

BITLESSON_CONTENT="$(cat "$BITLESSON_FILE")"
if [[ -z "$(printf '%s' "$BITLESSON_CONTENT" | tr -d ' \t\n\r')" ]]; then
echo "Error: BitLesson file is empty (whitespace only): $BITLESSON_FILE" >&2
exit 1
fi

# ========================================
# Detect Project Root (for -C)
# ========================================
Expand Down Expand Up @@ -148,6 +163,7 @@ $BITLESSON_CONTENT
1. Match only lessons that are directly relevant to the sub-task scope and failure mode.
2. Prefer precision over recall: do not include weakly related lessons.
3. If nothing is relevant, return \`NONE\`.
4. Use only the information in this prompt. Do not use tools, shell commands, browser access, MCP servers, or repository inspection.

## Output Format (Stable)

Expand All @@ -164,21 +180,35 @@ EOF

SELECTOR_TIMEOUT=120

CODEX_EXIT_CODE=0
if [[ "$BITLESSON_PROVIDER" == "codex" ]]; then
CODEX_EXEC_ARGS=("-m" "$BITLESSON_MODEL" "-c" "model_reasoning_effort=high")
run_selector() {
local provider="$1"
local model="$2"

if [[ "$provider" == "codex" ]]; then
local codex_exec_args=(
"--disable" "codex_hooks"
"--skip-git-repo-check"
"--ephemeral"
"-s" "read-only"
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 Probe Codex capabilities before passing new exec flags

bitlesson-select.sh now always invokes codex exec with --disable codex_hooks, --skip-git-repo-check, --ephemeral, and -s read-only. If the installed/stubbed Codex CLI does not support any of these flags, the selector exits non-zero before emitting LESSON_IDS/RATIONALE, which blocks BitLesson-gated work whenever bitlesson_model routes to Codex. This is a regression from the prior behavior because there is no compatibility probe/fallback on this path (unlike the stop-hook path).

Useful? React with 👍 / 👎.

"-m" "$model"
"-c" "model_reasoning_effort=low"
"-C" "$CODEX_PROJECT_ROOT"
)
printf '%s' "$PROMPT" | run_with_timeout "$SELECTOR_TIMEOUT" codex exec "${codex_exec_args[@]}" -
return $?
fi

# Determine automation flag based on environment variable (same as ask-codex.sh)
CODEX_AUTO_FLAG="--full-auto"
if [[ "${HUMANIZE_CODEX_BYPASS_SANDBOX:-}" == "true" ]] || [[ "${HUMANIZE_CODEX_BYPASS_SANDBOX:-}" == "1" ]]; then
CODEX_AUTO_FLAG="--dangerously-bypass-approvals-and-sandbox"
if [[ "$provider" == "claude" ]]; then
printf '%s' "$PROMPT" | run_with_timeout "$SELECTOR_TIMEOUT" claude --print --model "$model" -
return $?
fi
CODEX_EXEC_ARGS+=("$CODEX_AUTO_FLAG" "-C" "$CODEX_PROJECT_ROOT")

RAW_OUTPUT="$(printf '%s' "$PROMPT" | run_with_timeout "$SELECTOR_TIMEOUT" codex exec "${CODEX_EXEC_ARGS[@]}" -)" || CODEX_EXIT_CODE=$?
elif [[ "$BITLESSON_PROVIDER" == "claude" ]]; then
RAW_OUTPUT="$(printf '%s' "$PROMPT" | run_with_timeout "$SELECTOR_TIMEOUT" claude --print --model "$BITLESSON_MODEL" -)" || CODEX_EXIT_CODE=$?
fi
echo "Error: Unsupported BitLesson provider '$provider'" >&2
return 1
}

CODEX_EXIT_CODE=0
RAW_OUTPUT="$(run_selector "$BITLESSON_PROVIDER" "$BITLESSON_MODEL" 2>&1)" || CODEX_EXIT_CODE=$?

if [[ $CODEX_EXIT_CODE -eq 124 ]]; then
echo "Error: BitLesson selector timed out after ${SELECTOR_TIMEOUT} seconds" >&2
Expand All @@ -187,6 +217,7 @@ fi

if [[ $CODEX_EXIT_CODE -ne 0 ]]; then
echo "Error: BitLesson selector failed (exit code $CODEX_EXIT_CODE)" >&2
printf '%s\n' "$RAW_OUTPUT" >&2
exit "$CODEX_EXIT_CODE"
fi

Expand Down
Loading
Loading