Skip to content
Merged
4 changes: 3 additions & 1 deletion .claude/hooks/bash-guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"""
Claude Code PreToolUse Bash guard for Widthdom/CodeIndex.

Thin adapter around the shared CodeIndex guard core.
Tool-specific adapter around the shared guard core in
.agent_harness/command_guard_core.py. Codex uses the sibling adapter at
.codex/hooks/bash_guard.py.
"""

from __future__ import annotations
Expand Down
8 changes: 7 additions & 1 deletion .codex/hooks/bash_guard.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#!/usr/bin/env python3
"""Codex PreToolUse Bash guard for Widthdom/CodeIndex."""
"""
Codex PreToolUse Bash guard for Widthdom/CodeIndex.

Tool-specific adapter around the shared guard core in
.agent_harness/command_guard_core.py. Claude Code uses the sibling adapter at
.claude/hooks/bash-guard.py.
"""

from __future__ import annotations

Expand Down
36 changes: 36 additions & 0 deletions .codex/scripts/check-workflow-links.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"

status=0

while IFS= read -r doc; do
while IFS= read -r target; do
[[ -z "$target" ]] && continue
if [[ ! -s "$target" ]]; then
printf '%s references missing or empty workflow file: %s\n' "$doc" "$target" >&2
status=1
fi
done < <(
awk '
{
while (match($0, /`\.codex\/workflows\/[^`[:space:])]*\.md`/)) {
target = substr($0, RSTART + 1, RLENGTH - 2)
if (target !~ /[*?]/) {
print target
}
$0 = substr($0, RSTART + RLENGTH)
}
}
' "$doc" | sort -u
)
done < <(
{
git ls-files '*.md'
git ls-files '.codex/workflows/*.md'
} | sort -u
)

exit "$status"
5 changes: 5 additions & 0 deletions .codex/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This directory contains shared task workflows for CodeIndex coding agents.
Despite the `.codex` directory name, these workflows are used by both Codex and Claude Code.

Use these workflows instead of pasting long repeated instructions into every prompt.
Start from the thin entry point for your tool (`AGENTS.md` for Codex or `CLAUDE.md` for Claude Code), then follow `AGENT_GUIDE.md` to the relevant workflow here.

## Workflows

Expand All @@ -22,3 +23,7 @@ Use these workflows instead of pasting long repeated instructions into every pro
- Codex-specific entry instructions go in `AGENTS.md`.
- Claude-specific entry instructions go in `CLAUDE.md`.
- Do not duplicate full workflows across entry-point files.

## Link Checks

Run `bash .codex/scripts/check-workflow-links.sh` after renaming, adding, or removing workflow files. The check scans tracked Markdown entry points and workflow docs for `.codex/workflows/*.md` references and fails when a referenced workflow file is missing or empty.
1 change: 1 addition & 0 deletions .codex/workflows/precommit.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Run this before each commit.
10. Confirm issue auto-close references will be placed in the PR body as `Fixes #...`.
11. Confirm the commit message is English and includes relevant issue numbers.
12. Check `git diff --stat` and `git diff` for accidental changes.
13. If workflow file names or `.codex/workflows/*.md` references changed, run `bash .codex/scripts/check-workflow-links.sh`.

## Validation Commands

Expand Down
7 changes: 7 additions & 0 deletions AGENT_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ For implementation tasks:
## Workflow Index

Task-specific procedures live in `.codex/workflows/`. The directory is a shared workflow library for all coding agents, not only Codex.
See `.codex/workflows/README.md` for the workflow directory map and rule-placement guidance.

- issue fixing: `.codex/workflows/issue-fix.md`
- changelog fragments: `.codex/workflows/changelog-fragment.md`
Expand Down Expand Up @@ -55,6 +56,12 @@ This rule applies to code search and repository understanding. It does not forbi

## Tool-Specific Notes

Command-search enforcement is tool-specific and adapter-driven:

- Codex uses `.codex/hooks.json`, which invokes `.codex/hooks/bash_guard.py` and `.codex/hooks/permission_request_guard.py`.
- Claude Code uses `.claude/settings.json`, which invokes `.claude/hooks/bash-guard.py`.
- Both Bash guard adapters delegate shared command policy to `.agent_harness/command_guard_core.py`; update the shared core for common command policy and review both adapters only when tool-specific behavior changes.

### Claude Code

- Follow the repository-tracked `.claude/settings.json` and `.claude/hooks/bash-guard.py` policy files when running in Claude Code.
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ version 2.
| [Platform Support](docs/platform-support.md) | Official release asset RIDs, unsupported platforms, and source-build alternatives. |
| [Developer Guide](DEVELOPER_GUIDE.md) | Architecture, implementation notes, release workflow, and the [`reference_kind` filtering matrix](DEVELOPER_GUIDE.md#reference-kind-filtering-matrix) for `callers` / `impact` / `deps` count reconciliation. |
| [Testing Guide](TESTING_GUIDE.md) | Test conventions and validation commands. |
| [Agent Guide](AGENT_GUIDE.md) | Shared agent entry point, workflow index, search policy, and status contract maintenance rules. |
| [Claude Code Entry Point](CLAUDE.md) | Thin Claude Code entry point that redirects to the shared agent guide. |
| [Self-Improvement Contract](SELF_IMPROVEMENT.md) | Rules for agents improving CodeIndex itself. |
| [Integration Policy](INTEGRATION_POLICY.md) | Permitted CLI, JSON, MCP, and integration use. |
| [Security Policy](SECURITY.md) | Private vulnerability reporting and coordinated disclosure policy. |
Expand Down Expand Up @@ -323,6 +325,8 @@ hotspot-family readiness は、hotspot-family contract version 2 で導入され
| [プラットフォームサポート](docs/platform-support.md#プラットフォームサポート) | 公式リリースアセットの RID、未対応 platform、source build の代替手段。 |
| [開発者ガイド](DEVELOPER_GUIDE.md#開発者ガイド) | アーキテクチャ、実装メモ、リリース手順、`callers` / `impact` / `deps` の件数差を照合する [`reference_kind` フィルタの対応表](DEVELOPER_GUIDE.md#reference-kind-filtering-matrix)。 |
| [テストガイド](TESTING_GUIDE.md#テストガイド) | テスト規約と検証コマンド。 |
| [エージェントガイド](AGENT_GUIDE.md) | 共有エージェント入口、workflow index、検索ポリシー、status contract の保守ルール。 |
| [Claude Code 入口](CLAUDE.md) | 共有エージェントガイドへリダイレクトする薄い Claude Code entry point。 |
| [自己改善コントラクト](SELF_IMPROVEMENT.md#自己改善ループ) | CodeIndex 自身を改善するエージェント向けルール。 |
| [統合ポリシー](INTEGRATION_POLICY.md) | CLI、JSON、MCP、各種統合で許可される利用。 |
| [セキュリティポリシー](SECURITY.md) | 非公開の脆弱性報告と協調的開示の方針。 |
Expand Down
2 changes: 1 addition & 1 deletion SELF_IMPROVEMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The loop is not just "suggest ideas". It is:
- After every commit, rebuild `cdidx` from the latest local source, run `dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll status --check --json`, and refresh `.cdidx/codeindex.db` with that freshly built binary only when the check does not report `index_matches_workspace: true`.
- Prefer the lightest truthful refresh mode: use `--files` only for known in-place edits or new files, use `--commits HEAD` after a normal commit because it tracks renames/deletes from git history, use `--changed-between <old-ref> <new-ref>` after branch switches when both refs are known, and reserve a full `cdidx . --json` scan for history-moving operations or cases where repo-wide stale files must be purged.
- Prefer the **locally built latest binary** (`dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll`) over an older globally installed `cdidx` whenever the repository code has changed. **Never fall back to a global `cdidx`** — the global version may have an older DB schema, missing query features, or stale extraction logic that silently produces wrong results. This is enforced at the Claude Code harness level via the repo-tracked `.claude/settings.json`, which denies the full set of shell code-search and file-discovery commands: `rg`, `grep`, `egrep`, `fgrep`, `zgrep`, `rgrep`, `ripgrep`, `ag`, `ack`, `ack-grep`, `git grep`, `find`, `locate`, `mlocate`, `mdfind`, and `cdidx`. Use the built-in Grep / Glob tools or the locally built binary instead.
- Treat repo-tracked `.claude/settings.json` and `.claude/hooks/bash-guard.py` as policy files. Do not edit them during ordinary self-improvement work unless the task is explicitly about Claude Code guard behavior. The current guard is deny-oriented: it is intentionally permissive for routine `dotnet`, `git`, `gh`, `codex exec`, `/tmp` work, and read-only shell inspection, while still blocking dangerous shell patterns and sensitive local read paths.
- Treat repo-tracked `.claude/settings.json`, `.claude/hooks/bash-guard.py`, `.codex/hooks.json`, and `.codex/hooks/bash_guard.py` as tool-specific guard adapters. Do not edit them during ordinary self-improvement work unless the task is explicitly about agent guard behavior. Shared Bash command policy lives in `.agent_harness/command_guard_core.py`; update that shared core for common policy and review both adapters only when tool-specific behavior changes. The current guard is deny-oriented: it is intentionally permissive for routine `dotnet`, `git`, `gh`, `codex exec`, `/tmp` work, and read-only shell inspection, while still blocking dangerous shell patterns and sensitive local read paths.
- Respect the current local-privacy boundary in Claude Code: home-directory personal areas and credential-like files are intentionally read-denied by policy. Do not weaken those restrictions as a convenience workaround for self-improvement tasks; if the task genuinely requires changing the guard, treat that as the task itself and update docs accordingly.
- After `git switch`, re-index with the **locally built binary** using `dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll index . --changed-between <old-ref> <new-ref> --json` when the workflow has both the previous and current refs; this updates only the files changed between branches while still purging rename/delete old paths included by git. If the refs are not available, or after `git reset`, `git rebase`, `git commit --amend`, or `git merge`, use `dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll . --json` so stale files are purged against the current checkout.
- When searching and navigating code to investigate bugs, plan fixes, or verify changes, always use the **locally built binary** — not the globally installed version. This ensures query results reflect the latest extraction rules and DB schema from this branch.
Expand Down
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1906.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: fixed
issues:
- 1906
---

## English

- Added the shared agent guide and Claude Code entry point to the README documentation table.

## 日本語

- README のドキュメント表に共有エージェントガイドと Claude Code 入口を追加しました。
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1979.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: fixed
issues:
- 1979
---

## English

- Added a workflow link check script and precommit reminder so `.codex/workflows/*.md` references fail fast when targets are missing or empty.

## 日本語

- `.codex/workflows/*.md` 参照先の欠落や空ファイルを早期に検出できるよう、workflow link check script と precommit の確認項目を追加しました。
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1995.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: fixed
issues:
- 1995
---

## English

- Documented the Codex and Claude Code Bash guard adapters and their shared guard core to reduce policy drift.

## 日本語

- Codex と Claude Code の Bash guard adapter と共有 guard core を明記し、ポリシーの drift を抑えました。
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1997.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: fixed
issues:
- 1997
---

## English

- Clarified the command-guard enforcement boundary between Codex hooks and Claude Code settings.

## 日本語

- Codex hooks と Claude Code settings の command guard enforcement boundary を明確にしました。
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1998.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: fixed
issues:
- 1998
---

## English

- Cross-linked the shared agent guide and workflow directory README for easier workflow discovery.

## 日本語

- workflow を見つけやすくするため、共有エージェントガイドと workflow directory README を相互にリンクしました。
13 changes: 13 additions & 0 deletions changelog.d/unreleased/2677.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: fixed
issues:
- 2677
---

## English

- Made fuzzy suggestion duplicate diagnostics tolerate unavailable stderr so deduplication does not fail during parallel test output capture.

## 日本語

- fuzzy suggestion duplicate の診断出力で stderr が利用できない場合を許容し、並列テストの出力 capture 中に重複排除が失敗しないようにしました。
21 changes: 19 additions & 2 deletions src/CodeIndex/Cli/SuggestionStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -460,14 +460,31 @@ private static (SuggestionRecord? Record, double? Score) FindDuplicate(

if (best != null && bestScore >= threshold)
{
Console.Error.WriteLine(
$"cdidx: fuzzy suggestion duplicate matched hash {best.Hash} with score {bestScore:0.###} (threshold {threshold:0.###})");
WriteFuzzyDuplicateWarning(best.Hash, bestScore, threshold);
return (best, bestScore);
}

return (null, null);
}

private static void WriteFuzzyDuplicateWarning(string hash, double score, double threshold)
{
try
{
Console.Error.WriteLine(
$"cdidx: fuzzy suggestion duplicate matched hash {hash} with score {score:0.###} (threshold {threshold:0.###})");
}
catch (ObjectDisposedException)
{
// Best-effort diagnostic only; suggestion deduplication must not fail
// because another thread or test fixture temporarily replaced stderr.
}
catch (IOException)
{
// Same rationale as ObjectDisposedException.
}
}

private static bool SameDedupScope(SuggestionRecord left, SuggestionRecord right)
=> string.Equals(left.Category?.Trim(), right.Category?.Trim(), StringComparison.OrdinalIgnoreCase)
&& string.Equals(left.Language?.Trim() ?? string.Empty, right.Language?.Trim() ?? string.Empty, StringComparison.OrdinalIgnoreCase);
Expand Down
29 changes: 29 additions & 0 deletions tests/CodeIndex.Tests/SuggestionStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,35 @@ public void TryAddAndSubmit_FuzzyDuplicate_ReturnsMatchedHashAndScore()
Assert.True(second.DuplicateScore >= SuggestionStore.DefaultDedupThreshold);
}

[Fact]
public void TryAddAndSubmit_FuzzyDuplicate_IgnoresClosedDiagnosticStderr()
{
var originalError = Console.Error;
var closedError = new StringWriter();
closedError.Dispose();

lock (TestConsoleLock.Gate)
{
Console.SetError(closedError);
try
{
var record1 = MakeRecord("language_support", "javascript", "missing arrow function support");
var record2 = MakeRecord("language_support", "javascript", "arrow functions not supported");

var first = _store.TryAddAndSubmit(record1, null);
var second = _store.TryAddAndSubmit(record2, null);

Assert.True(first.IsNew);
Assert.False(second.IsNew);
Assert.Equal(record1.Hash, second.DuplicateOfHash);
}
finally
{
Console.SetError(originalError);
}
}
}

[Fact]
public void TryAdd_DifferentSuggestions_BothSucceed()
{
Expand Down
Loading