Adopt CASAN like a normal tool (codegraph-style): install the harness ONCE
per machine, then `casan init` per project writes CONFIG ONLY — the harness
is no longer copied into every repo.
- install.sh / install.ps1: global bootstrap (curl|sh / irm|iex or local
source). Installs harness to $CASAN_HOME/versions/<ver>, writes a `casan`
launcher that resolves the shared harness + the current project's .specify,
and records a gate-code integrity hash. CASAN_NO_PATH_LINK for tests.
- harness_hash.py: deterministic content hash over gate code (scripts/bash,
scripts/python, security, level5) — the pin+verify anchor.
- casan-init.py: `casan init` writes .casan/{config,version.lock,agentic.env},
.specify/ marker, and the Plan-20 client hooks — no harness copy. `verify`
recomputes the harness hash LIVE and compares to the project pin (drift/
tamper -> rc 3), preserving the Plan-16 trusted-gates guarantee off-repo.
- bin/casan: new `init` and `verify-harness` commands.
- hybrid-install-tests.sh: 21/21 (install, config-only init, no-copy, pin,
verify ok, tamper drift, bridge runs against project state via global harness).
- docs: CASAN_INSTALL_HYBRID.md + Plan-21.
The path model (casan-paths.sh) already separated harness/state/domain roots,
so this is installer + init, not a core rewrite. Remote dist tarball, real
Windows run, and signed .harness-hash are the documented next steps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wide-deployment Windows path without WSL2. The agentic bridge already runs
on native Python + PowerShell; the only bash dependency is the H4/H2 gate
scripts, which run under Git Bash (Git for Windows) — much lighter than WSL2.
- h4_scan now returns a status (ok|blocked|timeout|unavailable). Timeout stays
FAIL-CLOSED (block/deny). "unavailable" (no bash / gate missing) DEGRADES the
turn to observed_only and does NOT block the developer — never silently
certifies without a working gate.
- bash interpreter is configurable via CASAN_AGENTIC_BASH; gates use it.
- doctor reports bash_available / gates_runnable + a remediation warning, and
stays green (degraded, not failed) when bash is absent.
- tests: +4 no-bash cases (degrade to observed_only, tool still allowed,
non-certified finalize, injection still blocked when bash present). 34/34.
- docs: Windows guide + security guide now point to Git Bash, not WSL2, and
document the timeout-vs-unavailable distinction.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wave 0 + Wave 1 core of the transparent agentic-client integration: a
developer types prompts normally in Claude Code / Codex while every
certified turn still carries a full H1->H7 trace and an H6 record.
- agentic_bridge.py: stdlib-only lifecycle state machine (begin/pre-tool/
post-tool/telemetry/finalize/abort + report/doctor). Single-model
invariant (never calls a model), fail-closed at the side-effect point,
admission TTL + canonical-project/session binding, atomic state under
.specify/state/agentic-sessions/, secret redaction, null-not-zero H6.
- agentic-lifecycle.schema.json: client-agnostic JSON contract.
- adapters/claude-code + adapters/codex: thin hook renderers + config
templates that call the core bridge.
- phase-agentic-bridge-tests.sh: C1-C12 acceptance + threat suite (30/30).
- devkit templates/{claude,codex} + windows/install-agentic.ps1
(install/doctor/uninstall with manifest, path-safe).
- docs/casan Windows + security/bypass guides; plan status -> IMPLEMENTED.
- harden generate-agentops-dashboard.py aggregation against null H6 costs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
.gitea/workflows/release.yml — on push tag v*: assert tag==VERSION, run the governance
gate (must be green), build core/devkit/platform-preview/all-in-one-demo (enterprise
skipped/refused), then PUT each .tar.gz (+.sha256) to the Gitea generic package registry
using ${{ secrets.GITEA_TOKEN }}. Portable via GITHUB_SERVER_URL/OWNER. Guide updated with
the one-time secret setup + release flow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The policy bundle listed the 8 governed policy files under .specify/... (pre-restructure).
After the move they live in packages/casan-harness/. Repoint all 8 paths and re-sign the
manifest. This MUST be committed as its own step: phase-sec09/sec29 cleanup runs
`git checkout -- .specify/level5/central-governance/`, which restored the bundle to HEAD on
every gate run — so the fix only sticks once HEAD itself carries the corrected, re-signed
bundle. sign-policy-bundle verify → POLICY_SIGNATURE_VALID.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Organize CASAN as a reusable source hub with SPLIT releases so downstream adopts only the
level it needs (packaging/levels.json is the single source of truth).
Implemented now:
- Level 1 Core: bin/casan CLI (run/gate/test/verify/reuse/dashboard) + VERSION.
- Level 2 DevKit: packages/casan-devkit (install.sh, Dockerfile.harness, templates:
project scaffold, domain-pack, gitea-workflow).
- scripts/package-release.sh core|devkit|platform|all-in-one-demo — builds split bundles
into dist/ (BUNDLE-MANIFEST + SHA256SUMS); platform is stamped PREVIEW/INCOMPLETE;
enterprise (future) is REFUSED (exit 3, no fake-complete package). Bundles verified:
extract → bin/casan works, deterministic + domain suites pass, casan reuse VALID.
- docs/packaging: CASAN_PACKAGING_PLAN + ADOPTION + CI + DOMAIN_PACK + GITEA_PACKAGE + DOCKER.
Structure + docs only:
- Level 3 packages/casan-platform (dashboard exists; control-panel/viewers pending).
- Level 4 packages/casan-enterprise (RBAC/tenant/KMS/WORM/approval exist in core; governed
console pending). No Chat Console/RBAC-console/tenant-console/model-mgmt built in this task.
Harness change (enables extracted bundles to self-resolve): casan-paths.sh + the Python
project_root() walk-ups now accept a second root marker `packages/casan-harness` in addition
to `.specify`, so a freshly-unpacked core/devkit/demo bundle (no `.specify` yet) roots
correctly and creates state on first run. In an adopted repo `.specify` still matches first.
policy-bundle.yaml paths corrected to packages/casan-harness (re-signed). Full gate 64/0/3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two reference notes kept (per review); other scattered root notes and optimize-docs
(competition/video material) remain in git history only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The plan set (Plan-00..18, backlog/hardening/QA status, team allocation) is the ONGOING
roadmap, not a finished competition artifact — restored from history into docs/plans/.
Plan-01 (restructure) marked ✅ done; the rest remain to do.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point the canonical entry points at the new package layout; the .specify compat facade
is retained as an intentional backward-compat layer (see below).
- .gitea/workflows/{ci,harness-ci}.yml: invoke packages/casan-harness/scripts/bash|tests
(state paths .specify/logs kept). CI now runs on the new structure.
- infra/local-prod/docker-compose.yml: dashboard-server.py -> packages path (logs/alerts
env stay under .specify state).
- scripts/casan-step.mjs + run-casan-pipeline.mjs: resolve the harness under
packages/casan-harness, falling back to .specify so the adversarial/sourcegen sandboxes
(which stage a .specify/ tree) keep working; requirement input prefers apps/okr/domain/input.
- project-registry.json: record the new layout (harness_root, state_root, governance_root,
per-project domain_root) so Plan-06 can register a second app with its own domain.
verify-harness-reuse.sh already resolves via CASAN_HARNESS_ROOT -> HARNESS_REUSE_VALID (3 projects).
Facade decision: the .specify/{scripts,tests,security,...} symlinks are KEPT as a
documented compat layer. A full hard cutover (removing them) still needs ~15 literal
`.specify/...` refs repointed (loop_common/evidence-pack/secrets-scan config+test paths,
run-casan-pipeline step scripts, and the signed policy-bundle.yaml path list which then
needs manifest regen + re-sign). That is a scoped follow-up; the physical separation
(code in packages/, domain in apps/, packages holds no domain data, single CASAN_* path
indirection) is complete and the full gate is green via BOTH entry paths: PASS=64 FAIL=0 SKIP=3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve every root by marker walk-up instead of a fixed depth that only lands on the
app via the .specify compat symlink, so the harness runs correctly when invoked by its
real packages/casan-harness path — proven by a full gate run via that path: 64/0/0.
- 95 scripts/tests: PROJECT_ROOT/ROOT "$SCRIPT_DIR/../.."-style computations -> $CASAN_APP_ROOT.
- 6 leaf scripts (infra-lab, context-validate, secrets-scan, path-guard, toolchain-verify,
phase2-sourcegen) now source casan-paths + use CASAN_APP_ROOT.
- run-casan4: source casan-paths as a package sibling (facade-independent), PROJECT_ROOT=CASAN_APP_ROOT.
- 8 Python files: project_root()/REPO_ROOT/bundle_root walk UP for the .specify marker
(control-plane-settings, loop_common, model-call, context-compress, test-integrity,
bundle-integrity, traceability-matrix; generate-* fixed earlier).
- evidence-pack-build.py + traceability-matrix.py: domain refs -> apps/okr/domain
(input/, corpus/redteam-vectors.jsonl, traceability-map.json).
- ci-harness-gate.sh: export CASAN_TESTS_DIR/CASAN_TEST_MANIFEST/CASAN_BUNDLE_ROOT so the
integrity Python resolves via the harness root regardless of invocation path; ROOT=CASAN_APP_ROOT.
- Remove the domain compat symlinks from packages/casan-harness/security (redteam-corpus,
redteam-vectors, benign-corpus) — packages now holds NO domain data.
Both invocation paths pass (compat facade still present): .specify/... and packages/...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Separate per-project domain data from the reusable harness so packages/casan-harness
holds no domain artifacts. Domain data physically relocated to apps/okr/domain, with
compat symlinks at the old paths (Python + app + evidence-log refs keep resolving).
Moved -> apps/okr/domain (+ compat symlink at old path):
golden-runs/ (was .specify/level5/golden-runs)
corpus/{redteam-corpus.jsonl,redteam-vectors.jsonl,benign-corpus/}
(was packages/casan-harness/security/*)
traceability-map.json (was .specify/traceability-map.json)
input/ (was docs/input — OKR requirement/architecture)
casan-paths.sh: add CASAN_DOMAIN_ROOT (apps/okr/domain; env-overridable so Plan-06 can
point a second app at its own domain; falls back to .specify pre-split).
Harness bash refs repointed to $CASAN_DOMAIN_ROOT: run-casan4 (golden), phase3-redteam
(corpus), phase-h4-multilingual/split-inject (benign-corpus), phase10-traceability (map),
benign-fp-report (corpus+vectors). Python + app refs still resolve via the compat
symlinks (repointed in Phase 4 when the symlinks are removed).
Full gate: PASS=64 FAIL=0 SKIP=3 (CASAN_CI_STEP_TIMEOUT_SEC=1200). A first gate run
crawled under host load avg ~30 (Ollama + system); re-run at lower load passed clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the harness-config files out of the mixed .specify/level5 and .specify/agentops
dirs (which also hold governance/domain/state) into packages/casan-harness, leaving a
per-file compat symlink at each old path. Runtime state and governance stay in place.
Moved (+ .specify symlink each):
level5: drift-policy.yaml kpi-schema.yaml model-fallback.yaml tool-registry.yaml
harness-package.json project-registry.json provider-usage-sample.json
agentops: alerts.yaml hallucination-tracking.yaml metrics.yaml rate-limits.yaml tracking.yaml
top: init-options.json
Stays in .specify: level5/central-governance (governance), level5/golden-runs (domain,
Phase 3), agentops/alerts.log (state), traceability-map.json (domain, Phase 3).
Full gate: PASS=64 FAIL=0 SKIP=3 (CASAN_CI_STEP_TIMEOUT_SEC=1200).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Physically move the pure-code subtrees out of .specify into the package, leaving
compat symlinks at the old .specify/<dir> paths so every existing reference (internal
CASAN_HARNESS_ROOT + external CI/docker/mjs) keeps resolving. Runtime state stays put.
Moved (git mv): scripts/ tests/ security/ templates/ config/ governance/ memory/
.specify/<dir> -> packages/casan-harness/<dir> (+ .specify/<dir> symlink)
Stays in .specify (state/governance/domain, handled later): logs/ agentops/ level5/
init-options.json traceability-map.json
Python `.resolve()` self-location followed the compat symlink into packages and lost
the app root; generate-casan-demo-context.py, generate-agentops-dashboard.py and
dashboard-server.py now walk UP for the `.specify` state marker instead of a fixed
parent depth (fixes "missing trace files" in run-casan4).
Full gate: PASS=64 FAIL=0 SKIP=3 (CASAN_CI_STEP_TIMEOUT_SEC=1200 — track-a ~450s runs
close to the 600s default and can tip over under load; this is timing variance, not a
regression — it passed cleanly with headroom). Runtime log/audit artifacts kept unstaged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Task 1.2: introduce a single path resolver so no harness script hardcodes
`.specify/...` scattered across the tree. casan-paths.sh resolves four roots
(HARNESS/STATE/GOVERNANCE/APP) by marker-based walk-up from its own location —
never `git rev-parse` (git root is the repo PARENT here, not the app dir).
- 101 bash scripts/tests: 238 hardcoded `$PROJECT_ROOT/.specify/...` refs rewritten
to CASAN_HARNESS_ROOT (code) / CASAN_STATE_ROOT (logs,state) / CASAN_GOVERNANCE_ROOT.
Sandbox test vars ($WORK/$TP/$FP/$T1_WORK) left untouched.
- Roots are NOT exported: each script/subprocess self-resolves from its own tree,
matching the original per-script semantics and preserving hermetic sandbox isolation
(node casan-step.mjs, copied telemetry/rollback scripts must not inherit real roots).
- Sandbox tests that copy a harness script now also copy casan-paths.sh (its new
sibling dependency): adversarial (verify-audit-chain/verify-tool-audit/rollback) +
track-a (security-check/telemetry-integrity).
- control-plane-settings.json reclassified as STATE (untracked runtime store).
Roots all still resolve to `.specify` in this monolithic layout, so behavior is
unchanged. Full gate: PASS=64 FAIL=0 SKIP=3 (adversarial 44/0, track-a 25/0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Empty skeleton only (no file moves, no behavior change). Baseline gate
confirmed at PASS=64 FAIL=0 SKIP=3 (backend/frontend/infra off) before branch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Empty package/app skeleton for the harness restructure. No harness files moved yet; full gate baseline stays PASS=64 FAIL=0 SKIP=3. Subdirs materialize via git mv in Phases 1-5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SEC-12: drift-detect adds semantic invariants — negation-flip detection (a dropped
"not" now FAILS despite high char-similarity) + env must-keep patterns.
- SEC-29 (X-05): governance-check audit write fails CLOSED — an unwritable audit log
denies the action and empties the output (no unaudited output).
- SEC-30 (X-06): approval-verify records a one-time-use nonce (sha of token/sig) and
rejects replays (enforced mode / when a nonce ledger is set); dev unchanged.
- SEC-15 (low): typosquat distance<=2 with the levenshtein length-sentinel bug fixed
(no false positives); tool-exec fails closed with no timeout backend in enforced
mode; validate-tool-input now validates nested objects/arrays recursively.
Verify: new SEC suites all green via gate, run-casan4 0-FAIL, adversarial 44/44,
track-c 29/0, h5-approval 12/0, no regressions.
Plan-16 P2 remaining: infra-gated only (SEC-14/22/23/24/25/26).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SEC-07 (M-08): real approval verification via approval-verify.sh in enforced mode
(CASAN_PROFILE=prod / CASAN_APPROVAL_STRICT=1) for control-plane `set` (sensitive
keys), kill-switch `clear`, and self-improve (inherits control-plane). A bare or
forged approval string is now denied; dev mode stays backward-compatible.
- SEC-10 (M-05): non-spoofable agent identity. tool-registry-gate least-privilege no
longer trusts CASAN_AGENT env in enforced mode (CASAN_IDENTITY_STRICT=1) — the
caller must present a signed token (agent-identity-sign.sh) bound to agent id +
run id, verified against agent-identities.registry. Blocks env spoofing + replay.
Verify: SEC+integrity gate 18/0, run-casan4 0-FAIL, adversarial 44/44 (H2 intact),
control-plane 9/0, h5-approval 12/0, c7-incident 15/0, self-improve 7/0, track-c 29/0.
Plan-16 P0 + P1 now complete; remaining: P2 (SEC-12/13/14/15/22..30).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>