Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
50 changes: 50 additions & 0 deletions ftl_code_expert/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2986,6 +2986,51 @@ def _build_negative_issue_body(belief: dict) -> str:
return "\n".join(lines)


def _ensure_labels(platform: str, repo_slug: str, required: set[str]) -> None:
"""Create any missing labels on the target repo."""
if platform == "github":
result = subprocess.run(
["gh", "label", "list", "--repo", repo_slug, "-L", "1000",
"--json", "name", "-q", ".[].name"],
capture_output=True, text=True,
)
existing = set(result.stdout.strip().splitlines()) if result.returncode == 0 else set()
for label in required - existing:
click.echo(f" Creating label: {label}", err=True)
r = subprocess.run(
["gh", "label", "create", label, "--repo", repo_slug,
"--description", "Auto-created by code-expert file-issues"],
capture_output=True, text=True,
)
if r.returncode != 0:
click.echo(f" Failed to create label {label}: {r.stderr.strip()}", err=True)
elif platform == "gitlab":
result = subprocess.run(
["glab", "label", "list", "--repo", repo_slug, "-F", "json"],
capture_output=True, text=True,
)
existing: set[str] = set()
if result.returncode == 0 and result.stdout.strip():
try:
parsed = json.loads(result.stdout)
if isinstance(parsed, list):
for item in parsed:
if isinstance(item, dict):
name = item.get("name", "")
if name:
existing.add(name)
except (json.JSONDecodeError, TypeError, AttributeError):
pass
for label in required - existing:
click.echo(f" Creating label: {label}", err=True)
r = subprocess.run(
["glab", "label", "create", "--name", label, "--repo", repo_slug],
capture_output=True, text=True,
)
if r.returncode != 0:
click.echo(f" Failed to create label {label}: {r.stderr.strip()}", err=True)


def _create_issue(platform: str, repo_slug: str, title: str, body: str,
labels: list[str]) -> str | None:
"""Create an issue and return its URL, or None on failure."""
Expand Down Expand Up @@ -3494,6 +3539,11 @@ def file_issues(ctx, repo_slug, platform_override, labels, dry_run, skip_confirm
click.echo(f" {unconfirmed} belief(s) no longer present in code", err=True)
remaining = confirmed

# Ensure required labels exist
if not dry_run and remaining:
required_labels = {"reasons-gate", "reasons-negative"} | set(labels)
_ensure_labels(platform, repo_slug, required_labels)

# File issues
filed = []
skipped_ids = list(existing)
Expand Down
39 changes: 39 additions & 0 deletions ftl_code_expert/data/CLAUDE.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,45 @@ reasons compact
code-expert update --since-last # walk commits + propose + derive + summary
code-expert generate-summary # standalone morning summary

# Verification
code-expert verify <belief-id> # check one belief against current code
code-expert verify --all # verify all IN beliefs
code-expert verify --gated # verify beliefs blocking downstream chains
code-expert verify --negative --retract # verify negative beliefs, retract stale ones
code-expert infer-sources --all # infer source files for beliefs missing them

# Status
code-expert status
```

## Using the Reasons Database

When a `reasons.db` exists, **search beliefs before reading code**. The belief network contains verified claims about the codebase — architecture, patterns, bugs, invariants — that persist across sessions.

### Answering questions about the code

1. `reasons search "<question>"` — find beliefs relevant to the question
2. `reasons show <belief-id>` — read the full belief, its justification chain, and metadata
3. `reasons explain <belief-id>` — trace why a belief is IN or OUT
4. Read the actual source code to confirm the belief still holds
5. If a belief is stale, run `code-expert verify <belief-id>` to formally check it

### Before modifying code

1. `reasons search "<area being changed>"` — find beliefs about the affected code
2. Check for negative beliefs (bugs, gaps, risks) that the change might interact with
3. Check for gated beliefs — changes might unblock or break downstream reasoning chains
4. After making changes, verify affected beliefs: `code-expert verify --category <keyword>`

### Key reasons commands

```bash
reasons search "thread safety" # semantic search across all beliefs
reasons show <id> # full details including dependents
reasons explain <id> # trace justification chain (why IN or OUT)
reasons list # all nodes with status
reasons list --negative # bugs, gaps, risks
reasons list --gated # beliefs blocked by negative findings
```

The belief network is the project's accumulated knowledge. Searching it first avoids re-discovering what is already known and surfaces constraints that pure code reading would miss.