Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
667a3b9
feat(#135): dashboard tooltip nudges out-of-session committers to /bi…
jinhongkuan Apr 30, 2026
aebd94b
feat(#108): end-to-end sim + capture-corrections skill correction
jinhongkuan Apr 30, 2026
78b6c09
style(#108): ruff format scripts/sim_issue_108_flows.py + docstring sync
jinhongkuan Apr 30, 2026
6163002
fix(#108): portable repo-root resolution in sim_issue_108_flows.py
jinhongkuan May 1, 2026
ad3e440
chore: bump to v0.13.6 — triage release (#135, #108)
jinhongkuan May 1, 2026
aa74510
fix(skill): resolve preflight auto-fire failure on natural refactor p…
Knapp-Kevin May 2, 2026
c5c86f7
fix(setup): install preflight UserPromptSubmit hook for end users
jinhongkuan May 2, 2026
d014299
style: ruff format scripts/hooks/preflight_intent.py
jinhongkuan May 2, 2026
a50d723
fix(e2e): materialize UserPromptSubmit hook into test target settings
jinhongkuan May 2, 2026
697dc6e
fix(hook): emit hookSpecificOutput envelope so additionalContext reac…
jinhongkuan May 2, 2026
f97ddab
test(e2e): split Flow 2 into auto-fire (Flow 2) + correction-capture …
jinhongkuan May 2, 2026
e961cad
style: ruff format tests/e2e/run_e2e_flows.py
jinhongkuan May 2, 2026
cf48270
fix(hooks): SessionEnd hook drift — re-entrancy guard + --auto-ingest…
Knapp-Kevin May 2, 2026
17907fb
test(e2e): add Flow 4 path-X-(b) ledger validation (#147)
Knapp-Kevin May 2, 2026
82a493e
test(e2e): bootstrap .bicameral/ + pass --mcp-config to SessionEnd su…
Knapp-Kevin May 2, 2026
975dc83
test(e2e): point Flow 4 advisory at #156 (design pivot) instead of #154
jinhongkuan May 2, 2026
e72a418
refactor(e2e): single source of truth for harness + recording setup
jinhongkuan May 2, 2026
c95c6a8
fix(skill): capture refinements when prompt contradicts surfaced deci…
jinhongkuan May 3, 2026
e7323c8
test(e2e): rewrite demo flow prompts in realistic per-role voice
jinhongkuan May 3, 2026
0b79e35
feat: carry over v0 CI workflows + demo recording + dev-cycle docs fr…
jinhongkuan May 3, 2026
e7f0969
fix(ci): carry over missing tests/e2e/bicameral.mcp.json from dev
jinhongkuan May 3, 2026
3b3e8dc
fix(ci): wire ruff + mypy into [test] extra and add config sections
jinhongkuan May 3, 2026
6cb0e5f
fix(e2e): bump claude CLI flow timeout 300s → 480s
jinhongkuan May 3, 2026
9901fb6
Merge pull request #171 from BicameralAI/fix/flow1-asserter-relax-fea…
jinhongkuan May 3, 2026
2b20bb2
Merge pull request #168 from BicameralAI/fix/154-postflight-capture-hook
jinhongkuan May 3, 2026
b178e13
Merge pull request #172 from BicameralAI/fix/preflight-after-discovery
jinhongkuan May 4, 2026
b3fb654
Merge pull request #174 from BicameralAI/feat/preflight-graph-expansion
jinhongkuan May 4, 2026
c7d1274
Merge branch 'main' into triage-from-dev
jinhongkuan May 4, 2026
3a44116
style(ci): apply ruff fixes + format to unblock lint workflow on tria…
May 4, 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
23 changes: 21 additions & 2 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@
"hooks": [
{
"type": "command",
"command": "python3 -c \"import json,sys,re; d=json.load(sys.stdin); c=d.get('tool_input',{}).get('command',''); ops=('git commit','git merge ','git pull','git rebase --continue'); [print('bicameral: git write-op detected — call bicameral.link_commit(commit_hash=\\'HEAD\\') now to sync the decision ledger') for _ in [1] if any(op in c for op in ops)]\""
"command": "python3 scripts/hooks/post_commit_sync_reminder.py"
}
]
},
{
"matcher": "mcp__bicameral__bicameral_preflight",
"hooks": [
{
"type": "command",
"command": "python3 scripts/hooks/post_preflight_capture_reminder.py"
}
]
}
Expand All @@ -16,7 +25,17 @@
"hooks": [
{
"type": "command",
"command": "[ -d .bicameral ] && claude -p '/bicameral:capture-corrections' || true"
"command": "[ -d .bicameral ] && [ -z \"$BICAMERAL_SESSION_END_RUNNING\" ] && BICAMERAL_SESSION_END_RUNNING=1 claude -p '/bicameral:capture-corrections --auto-ingest' || true"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "python3 scripts/hooks/preflight_reminder.py"
}
]
}
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/label-merged-to-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Apply merged-to-dev label

on:
pull_request:
branches: [dev]
types: [closed]

jobs:
label:
name: Label closed-by-PR issues
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
permissions:
issues: write
pull-requests: read
steps:
- name: Apply merged-to-dev label
uses: actions/github-script@v7
with:
script: |
// Workflow caveat: this job needs Settings -> Actions ->
// General -> Workflow permissions set to "Read and write
// permissions" at the repo level. The job-level
// `permissions: issues: write` block can only NARROW what
// the repo allows, never expand it. If the repo default
// is read-only, addLabels returns 403 "Resource not
// accessible by integration" regardless of the job-level
// grant.
//
// See: #115 (root cause + symptoms) and #104 (admin-side
// fix tracked alongside branch-protection setup).
//
// GitHub close keywords (case-insensitive): close, closes,
// closed, fix, fixes, fixed, resolve, resolves, resolved.
const pr = context.payload.pull_request;
const body = pr.body || "";
const closeRegex = /(?:close[sd]?|fix(?:es|ed)?|resolve[sd]?)\s+#(\d+)/gi;
const matches = [...body.matchAll(closeRegex)];
const issues = [...new Set(matches.map(m => parseInt(m[1])))];

const failed = [];
for (const num of issues) {
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: num,
labels: ["merged-to-dev"]
});
console.log(`Labeled #${num}`);
} catch (e) {
console.log(`Failed to label #${num}: ${e.message}`);
failed.push({ num, message: e.message });
}
}

if (failed.length > 0) {
const summary = failed
.map(f => ` - #${f.num}: ${f.message}`)
.join("\n");
throw new Error(
`merged-to-dev labeller could not label ${failed.length} ` +
`issue(s) referenced by PR #${pr.number}:\n${summary}\n\n` +
`Most likely cause: repo Settings -> Actions -> General -> ` +
`Workflow permissions is set to read-only. ` +
`Job-level "permissions: issues: write" cannot expand a ` +
`read-only repo default. See #104 (admin fix) and ` +
`#115 (root cause).`
);
}
24 changes: 24 additions & 0 deletions .github/workflows/lint-and-typecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Lint & Type Check

on:
pull_request:
branches: [main, dev]

jobs:
lint:
name: ruff + mypy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install
run: pip install -e ".[test]"
- name: Ruff check
run: ruff check .
- name: Ruff format check
run: ruff format --check .
- name: Mypy
run: mypy .
24 changes: 24 additions & 0 deletions .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Secret Scan

on:
pull_request:
branches: [main, dev]

# gitleaks-action@v2 requires a paid license for organizations
# (https://github.com/gitleaks/gitleaks-action#-announcement).
# We use trufflehog instead — free for all repos, equally capable
# detector ruleset, and faster cold-start than spinning up a
# gitleaks container.
jobs:
trufflehog:
name: TruffleHog
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history so trufflehog can scan the diff range
- uses: trufflesecurity/trufflehog@main
with:
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
extra_args: --only-verified
Comment on lines +20 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "secret-scan.yml" -type f

Repository: BicameralAI/bicameral-mcp

Length of output: 105


🏁 Script executed:

cat -n .github/workflows/secret-scan.yml | sed -n '15,30p'

Repository: BicameralAI/bicameral-mcp

Length of output: 518


🌐 Web query:

GitHub Actions best practices security pinning immutable commit SHA mutable branch @main``

💡 Result:

GitHub Actions security best practices emphasize pinning actions to full-length commit SHAs for immutability, rather than mutable branches like @main or tags, to prevent supply chain attacks where tags/branches are rewritten to malicious commits. Key recommendations: - Always pin actions to a full 40-character SHA: uses: actions/checkout@93cb6ef # v4 - Avoid @main, @master, @latest, or tags (@v1) unless you fully trust the maintainer, as they are mutable. - Add comments indicating the version for maintainability. - Use GitHub policies to enforce SHA pinning at repo/org level. - Tools like Dependabot/Renovate for updates; scripts to find unpinned uses. - For actions/checkout specifically, pin the action itself to SHA; the 'ref' input defaults securely to the triggering commit SHA ($GITHUB_SHA), which is immutable per run. - Branches like @main in triggers (on: push: branches: [main]) are standard and not a security risk for triggering, as workflows run on specific commits. Examples: Before (vulnerable): uses: actions/checkout@main or uses: actions/checkout@v4 After (secure): uses: actions/checkout@93cb6ef # v4.1.6 To get SHA: git ls-remote --tags https://github.com/actions/checkout.git refs/tags/v4

Citations:


🌐 Web query:

trufflesecurity trufflehog action GitHub releases versions

💡 Result:

TruffleHog GitHub releases (trufflesecurity/trufflehog) and what they mean for the TruffleHog GitHub Action. 1) GitHub release versions (as of 2026-05-03) - Latest release: v3.95.2 (shown as the latest release on the repository page). - Recent releases include: - v3.95.0 (published 2026-04-21). - v3.93.2 (published 2026-02-10). The authoritative source for “what versions have been released” is the GitHub Releases page for trufflesecurity/trufflehog. 2) TruffleHog GitHub Action: how “versions” are selected The TruffleHog GitHub Action is defined in the repository as a composite action (action.yml). It has an input named version, which defaults to "latest". When the action runs, it executes the TruffleHog CLI from the TruffleHog container image tag ghcr.io/trufflesecurity/trufflehog:${VERSION}. So: - Using trufflesecurity/trufflehog@main (or @vX.Y.Z for the action definition) controls the action workflow code. - The actual TruffleHog CLI version used at runtime is controlled by the action input version (default latest), which maps to a ghcr.io/trufflesecurity/trufflehog container tag. 3) Practical guidance (example) - To pin the TruffleHog CLI version used by the action: uses: trufflesecurity/trufflehog@main with: version: v3.95.0 Cited evidence - GitHub Releases page and release tag details show the release versions (e.g., v3.95.0) and the existence of releases. - The repository page indicates the latest release is v3.95.2. - The action.yml input "version" default is "latest", and the docker command runs ghcr.io/trufflesecurity/trufflehog:${VERSION}.

Citations:


Pin the TruffleHog action to an immutable revision.

Using trufflesecurity/trufflehog@main makes this required security check depend on upstream branch movement. A force-push or compromised upstream repo can silently change what runs in CI. Pin to a full commit SHA or an immutable release tag (e.g., @v3.95.2) instead.

Suggested change
-      - uses: trufflesecurity/trufflehog@main
+      - uses: trufflesecurity/trufflehog@v3.95.2
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: trufflesecurity/trufflehog@main
with:
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
extra_args: --only-verified
- uses: trufflesecurity/trufflehog@v3.95.2
with:
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
extra_args: --only-verified
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/secret-scan.yml around lines 20 - 24, The workflow uses an
unfixed ref `trufflesecurity/trufflehog@main` in
.github/workflows/secret-scan.yml which can change upstream; replace that
`uses:` value with an immutable release tag or full commit SHA (for example
`trufflesecurity/trufflehog@vX.Y.Z` or
`trufflesecurity/trufflehog@<full-commit-sha>`) so the TruffleHog action
invocation is pinned and reproducible, then commit the updated `uses:` line in
the secret-scan workflow.

22 changes: 18 additions & 4 deletions .github/workflows/test-mcp-regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ name: MCP Regression Tests

on:
pull_request:
branches: [main]
branches: [main, dev]

env:
PYTHON_VERSION: '3.11'

jobs:
mcp-tests:
name: MCP Regression Suite
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 20
# Needed so ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} / ANTHROPIC_API_KEY
# (environment secrets scoped to `ci-test`) is injected into the M1
# extraction step. The env is gate-free so this does not block
Expand Down Expand Up @@ -47,7 +52,10 @@ jobs:
# ── Clone OSS repos for eval ground truth ────────────────────────
# Only medusa is needed — saleor/vendure were used by eval_code_locator.py
# which was removed in v0.6.4 when search_code was nuked.
# Ubuntu-only: bash function syntax + medusa corpus consumed by
# the Linux-only M1 adversarial eval and E2E report below.
- name: Clone eval repos (shallow, pinned commits)
if: matrix.os == 'ubuntu-latest'
run: |
clone_at_commit() {
local repo_url=$1 dest=$2 commit=$3
Expand Down Expand Up @@ -80,6 +88,7 @@ jobs:
# "secret is not set" from "secret is set to empty string" from
# "secret is set correctly" without ever exposing the key.
- name: M1 secret visibility probe
if: matrix.os == 'ubuntu-latest'
run: |
set +e
if [ -n "${ANTHROPIC_API_KEY}" ]; then
Expand Down Expand Up @@ -109,6 +118,7 @@ jobs:
# as a red "M1 adversarial" step in the job without failing the
# whole build, so the rest of the regression suite still reports.
- name: M1 adversarial corpus eval (warn-only)
if: matrix.os == 'ubuntu-latest'
continue-on-error: true
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
Expand All @@ -120,8 +130,12 @@ jobs:
-o test-results/m1-adversarial.json

# ── Generate rich E2E report from artifacts ────────────────────
# Ubuntu-only: the script consumes the medusa adversarial corpus
# (cloned only on Ubuntu above) plus the Phase 3 E2E artifacts
# the report builds. Windows runs the unit + integration suite
# for cross-platform coverage but skips the corpus-driven E2E.
- name: Generate E2E report
if: always()
if: always() && matrix.os == 'ubuntu-latest'
run: python tests/generate_e2e_report.py

# ── Generate step summary from JUnit XML ───────────────────────
Expand All @@ -137,6 +151,6 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: mcp-test-results
name: mcp-test-results-${{ matrix.os }}
path: test-results/
retention-days: 30
Loading
Loading