Skip to content
Merged
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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,10 @@ jobs:
- uses: actions/checkout@v7
- name: Check version consistency
run: ./scripts/check-version.sh
planning-hygiene:
name: Planning Hygiene
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Check no tracked planning-plane references
run: bash scripts/check-planning-hygiene.sh
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ target/
# Cargo.lock

# -----------------------------------------------------------------------------
# Planning and Local Configuration (NEVER COMMIT)
# Planning and Local Configuration (kept out of the tree)
# -----------------------------------------------------------------------------
# Session planning documents - always local, never committed
.plans/
# Session planning documents are kept out of the working tree on purpose; this
# entry is a convenience filter, not a security boundary.
/.plans/

# Local agent instructions - per-session tactical guidance
AGENTS.local.md
Expand Down
1 change: 0 additions & 1 deletion .goneat/assess.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ lint:
ignore:
- "**/target/**"
- "**/.git/**"
- ".plans/**"
# GitHub Actions linting
github_actions:
actionlint:
Expand Down
15 changes: 12 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Read First

1. Check `AGENTS.local.md` if it exists (gitignored, tactical session guidance)
1. **Check for local guidance** if present (e.g. `AGENTS.local.md`) — machine-specific instructions and tactical session overrides. Local context is kept out of the working tree on purpose; a `.gitignore` entry is a convenience filter, not a security boundary.
2. Read `MAINTAINERS.md` for contacts and governance
3. Review this document for operational protocols
4. Understand: this is a **Rust library with cross-language bindings** — correctness is paramount
Expand Down Expand Up @@ -156,8 +156,8 @@ FFI boundary changes require extra scrutiny:
- Change FFI contracts without review
- Use `unsafe` without clear justification and review
- Assume platform behavior without testing
- **EVER commit anything from `.plans/`** - this directory is gitignored and MUST stay local
- Commit `AGENTS.local.md` (gitignored - session-specific guidance)
- **Add local planning paths, board names, or planning IDs to tracked content** — planning artifacts live in a private, maintainer-managed system kept outside the repository tree; a `.gitignore` entry is a convenience filter, not a security boundary
- Commit `AGENTS.local.md` or other local guidance — it is kept out of the tree as defense-in-depth, not because a `.gitignore` entry makes it safe

## Critical Rules

Expand Down Expand Up @@ -281,6 +281,15 @@ FFI Architect — Bindings design and cross-language integration.
- **FulmenHQ patterns**: https://github.com/fulmenhq/crucible
- **Local decisions**: `docs/decisions/` (ADR, DDR, SDR)

## Planning Artifacts

- Feature briefs, task boards, and operational notes live in a private,
maintainer-managed planning system kept **outside** this repository tree —
not in-tree behind `.gitignore`, which is a convenience filter, not a security
boundary. This conforms to the [3 Leaps OSS Sensitive Local Data Policy](https://github.com/3leaps/oss-policies/blob/main/SENSITIVE-LOCAL-DATA.md).
- Do not add local planning paths, board names, or planning IDs to tracked repo
content (code, docs, comments, commit messages, PR text).

## Contact

- **Lead maintainer**: See MAINTAINERS.md
Expand Down
49 changes: 49 additions & 0 deletions scripts/check-planning-hygiene.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
#
# Planning-reference hygiene guard.
#
# Planning artifacts (briefs, task boards, IDs, memos) live in a private,
# maintainer-managed system OUTSIDE this repository tree — see AGENTS.md →
# "Planning Artifacts". A `.gitignore` entry is a convenience filter, not a
# security boundary, so this guard asserts that no *tracked* file reintroduces
# a reference to the private planning plane.
#
# This file stays self-sterile: the guarded tokens are spelled with character
# classes ([.], [/], [-]) so the script never reintroduces the very substrings
# it guards. The single permitted tracked reference is the anchored ignore
# entry (an exact allowlist below), which names the retired directory as
# defense-in-depth; every other guarded hit must fail.
set -euo pipefail

pattern='[.]plans|planning[/]|brief[-]ipcp|IPCP[-]TASK|IPCP[-][0-9]'
permitted='^\.gitignore:[0-9]+:/[.]plans/$'

# Content: allow only the single anchored ignore entry; reject every other
# guarded hit in any tracked file.
hits="$(git grep -nE "$pattern" || true)"
if [ -n "$hits" ]; then
bad="$(printf '%s\n' "$hits" | grep -vE "$permitted" || true)"
if [ -n "$bad" ]; then
printf '%s\n' "$bad"
echo "::error::A tracked file references the private planning plane. Keep" \
"planning artifacts out of the repository tree (see AGENTS.md →" \
"Planning Artifacts)."
exit 1
fi
fi
perm_count="$(printf '%s\n' "$hits" | grep -cE "$permitted" || true)"
if [ "$perm_count" -ne 1 ]; then
echo "::error::Expected exactly one permitted ignore entry, found $perm_count."
exit 1
fi

# Paths: no tracked path may reintroduce a planning-plane directory segment
# (a content grep alone cannot see a sterile file added under a leaky path).
tracked_paths="$(git ls-files | grep -E "$pattern" || true)"
if [ -n "$tracked_paths" ]; then
printf '%s\n' "$tracked_paths"
echo "::error::A tracked file path references the private planning plane."
exit 1
fi

echo "OK: no private planning-plane references in tracked files."
Loading