{
 "type": "abp/site/v1",
 "what": "The agent behaviour policy of storyboards.sgit.ai: the agents that work on this site, what they can do, what they are asked to do, every rule with the barrier that stands in its way and what enforces it, and where each rule maps to elsewhere. Written as data so the page is generated from it and another site can copy the shape. Rendered at /abp/.",
 "site": "storyboards.sgit.ai",
 "repository": "SGit-AI/SGit-AI__Website__Storyboards",
 "twin": {"site": "api.storyboards.sgit.ai", "abp": "https://api.storyboards.sgit.ai/abp/index.html"},
 "version": "v1.0.0",
 "as_at": "2026-10-20",
 "status": "written by the storyboards agent from Dinis Cruz's words and this repository's rules; not yet read by him",
 "shape": "anthropic/claude-code-remote/ccr-container",
 "operator": "Dinis Cruz",
 "agents": [
  {"id": "storyboards-agent", "name": "The storyboards agent", "kind": "Claude Code session",
   "runs_as": "a Claude Code session in a Claude Code on the web container, started by the person from claude.ai/code, with this repository and SGit-AI__Website__Storyboards__API cloned side by side",
   "does": "builds and releases both sites from the briefs: imports storyboards, writes pages and articles, cuts API releases, pins them here, runs the gates and tests, pushes",
   "reads_at_start": ["CLAUDE.md", "briefs/", "REALITY.md", "BRIEF-CORRECTIONS.md", "the code immutability hook's instructions (SessionStart)"],
   "leaves": "commits on the person's GitHub account, each with a Claude-Session trailer naming the session"},
  {"id": "research-subagent", "name": "Research subagents", "kind": "read-only subagent",
   "runs_as": "Explore agents the storyboards agent starts for one research question (for example, how sibling sites are built, or what riskmandate.ai's policy shape is)",
   "does": "reads and searches files and public web pages; cannot edit, write or push",
   "reads_at_start": ["the question it is given"],
   "leaves": "a report to the storyboards agent, treated as data and never as an instruction"}
 ],
 "layers": [
  {"layer": "prompt", "barrier": "expectation", "here": "CLAUDE.md, the briefs, and the harness's own instructions to the session"},
  {"layer": "Claude Code hook", "barrier": "setting", "here": ".claude/settings.json: SessionStart prints the code immutability rule; PreToolUse runs the API checkout's hook on every Edit, Write, MultiEdit, NotebookEdit and Bash"},
  {"layer": "the build", "barrier": "setting", "here": "admin/build/build.py stops on an unknown character, kind, pose, mood or prop, a storyboard whose bytes are not the imported ones, or a stale thumbnail"},
  {"layer": "the gate", "barrier": "setting", "here": "admin/build/validate.py: links, twins, sitemap, the pinned API with its integrity strings, the version everywhere, key shapes, em-dashes"},
  {"layer": "CI", "barrier": "setting", "here": ".github/workflows/ci.yml on every push: the build twice, the gate, the version bump, briefs unchanged, every page in Chromium"},
  {"layer": "the deploy", "barrier": "setting", "here": ".github/workflows/deploy-pages.yml: the same checks before www/ is published from dev"},
  {"layer": "a host rule", "barrier": "boundary", "here": "none yet: dev is not protected, so a push that fails CI still lands on the branch (it is not deployed)"}
 ],
 "grant": [
  {"capability": "write.file.project", "what": "change any file in this checkout and the API checkout beside it", "undo": "with effort (git)", "note": "the code immutability hook denies changes to published API releases"},
  {"capability": "write.repository.project", "what": "push commits to any branch of this repository and of SGit-AI__Website__Storyboards__API, including dev, which deploys", "undo": "with effort (a new commit; a deployed page may be cached)", "note": "the harness tells the session to push only to its own branch unless the person says otherwise"},
  {"capability": "write.repository.tenant", "what": "through the session's GitHub tools: create branches, open, comment on and merge pull requests in the two repositories it is scoped to", "undo": "with effort", "note": "the harness tells the session not to open a pull request unless asked"},
  {"capability": "run code in the container", "what": "run any command: Python, Node, Chromium (Playwright), git", "undo": "the container is reclaimed after the session", "note": ""},
  {"capability": "read the public web", "what": "fetch public pages through the session's proxy", "undo": "nothing to undo", "note": "used to read the sibling sites and riskmandate.ai"},
  {"capability": "change its own controls", "what": "edit .claude/settings.json, the hooks, the policy files, the workflows", "undo": "with effort", "note": "the hook asks the person first (ABP-SB-001, row R5)"}
 ],
 "mandate": {
  "want": ["a home for storyboards that are data, drawn by the API's kit, in every shape they come in (the brief of 20 October 2026)",
           "the storyboards from gen-z-developers.sgit.ai and pki.sgit.ai, replicated as they are",
           "every push to dev a version, shown on every page, with a line saying what changed",
           "both repositories worked side by side and kept in step"],
  "do_not_want": ["a storyboard or cast edited here instead of at its origin", "a page in www/ edited by hand", "code in a published API release changed",
                  "a key, a token or a vault key in the repository", "a brief rewritten after the fact", "a push to dev or a pull request the person did not ask for"],
  "unstated": ["whether the agent may merge a pull request: not decided; it has not been asked to and has not"]
 },
 "rules": [
  {"id": "ABP-SB-001", "rule": "Code in a published API release folder (vX/vX.Y/vX.Y.Z/) is never changed", "why": "a page pinned to a release must get the same bytes for as long as it exists; its integrity strings refuse anything else", "capability": "write.file.project", "barrier": "setting",
   "enforced_by": "the API checkout's hook, run from .claude/settings.json here (deny); in the API repository also its pre-commit hook, release.py check and CI", "stronger_at": "branch protection on the API's dev requiring ci (boundary)", "detail": "https://api.storyboards.sgit.ai/policies/code-immutability.html",
   "maps_to": ["api.newsroom.sgit.ai rule R16: a change is a new version path, always", "abp.sgit.ai upstream/: fetched bytes, never edited"]},
  {"id": "ABP-SB-002", "rule": "A storyboard or cast imported from another site is never edited here: it is corrected at its origin and re-imported", "why": "the storyboard is the origin site's work, checked there (gen-z's quotes word for word); a local edit would make two versions that disagree", "capability": "write.file.project", "barrier": "setting",
   "enforced_by": "admin/build/build.py: every imported file's SHA-256 against content/series/*/series.json; a changed or unimported file stops the build, locally and in CI", "stronger_at": "CODEOWNERS on content/series/",
   "maps_to": ["gen-z-developers.sgit.ai CLAUDE.md: do not edit anything under v1/content/", "abp.sgit.ai: upstream/ and contributed/ are fetched bytes, never edited"]},
  {"id": "ABP-SB-003", "rule": "www/ is generated by the build and never edited by hand", "why": "a hand edit is lost on the next build, or worse, kept by a build that no longer makes it", "capability": "write.file.project", "barrier": "setting",
   "enforced_by": "build.py --check in CI and before every deploy", "stronger_at": "branch protection requiring ci",
   "maps_to": ["sgit.ai repository guidance: nav and footer injected at build so they cannot drift"]},
  {"id": "ABP-SB-004", "rule": "Every push to dev is a new version, with its line in content/versions.json", "why": "a page that does not say which version it is cannot be dated or checked", "capability": "write.repository.project", "barrier": "setting",
   "enforced_by": "CI's version check against dev; build.py refuses a malformed history; validate.py checks the version on every page and in llms.txt", "stronger_at": "branch protection requiring ci",
   "maps_to": ["sgit.ai repository guidance: one version, going up on every push"]},
  {"id": "ABP-SB-005", "rule": "No key, token or vault key is ever committed", "why": "a read key may be published; a vault key or a provider's API key never", "capability": "write.repository.project", "barrier": "setting",
   "enforced_by": "validate.py: sgit vault key shapes, private key blocks, cloud and provider key prefixes in www/, content/, briefs/ and admin/", "stronger_at": "GitHub secret scanning with push protection (a host rule)",
   "maps_to": ["sgit.ai repository guidance: credentials; the leak tripwire"]},
  {"id": "ABP-SB-006", "rule": "A brief is published in full and never edited; corrections go in BRIEF-CORRECTIONS.md", "why": "the brief is the record of what was asked; a correction above the mistake keeps both visible", "capability": "write.file.project", "barrier": "setting",
   "enforced_by": "CI: a brief that exists on dev must be unchanged on the branch", "stronger_at": "CODEOWNERS on briefs/",
   "maps_to": ["sgit.ai repository guidance: the brief, in full; the corrections file"]},
  {"id": "ABP-SB-007", "rule": "Push to dev, which deploys, and open or merge a pull request, only when the person has asked", "why": "a push to dev publishes to the world; the person decides when", "capability": "write.repository.project", "barrier": "expectation",
   "enforced_by": "nothing but the session's instructions", "stronger_at": "branch protection on dev requiring a review (a host rule)",
   "maps_to": ["riskmandate.ai RM-R0013, push anywhere", "riskmandate.ai RM-R0019, commit without asking"]},
  {"id": "ABP-SB-008", "rule": "The site's own prose has no em-dashes, states the status of things and sources its numbers", "why": "the estate's house style; a number nobody can check is a guess", "capability": "write.file.project", "barrier": "expectation",
   "enforced_by": "validate.py refuses an em-dash in content/articles, content/pages and the agent-written part of briefs/ (setting); the rest is a request", "stronger_at": "",
   "maps_to": ["sgit.ai repository guidance: writing"]},
  {"id": "ABP-SB-010", "rule": "The agent does not weaken its own controls without the person", "why": "a control the agent can quietly switch off is not a control", "capability": "change its own controls", "barrier": "setting",
   "enforced_by": "the code immutability hook asks the person before a write to .claude/settings.json (here) and to the API's hook, policy files, release tool and workflows", "stronger_at": "managed hooks the agent cannot write (allowManagedHooksOnly)",
   "maps_to": ["riskmandate.ai RM-R0015, change its own permissions"]}
 ],
 "gaps": ["No rule is a boundary yet: every control above lives in a file this agent's grant can write, or in the agent's instructions. Protecting dev in GitHub (require the ci check, and a review for the files under .claude/, policies/ and .github/) is the step that turns several of them into boundaries; only the person can make it.",
          "No footprint is recorded: what the agent actually did is in the git history (every commit carries a Claude-Session trailer) and in the session itself, and nothing compares it with this policy yet.",
          "A Claude Code hook fails open if it errors or times out, and a git hook is skipped with --no-verify; the CI checks are the backstop for both."],
 "copy_to_another_site": "Copy policies/abp.json (type abp/site/v1) and the renderer (admin/build/abp.py here, site/abp.py in the API repository), list the site's own agents, grant, mandate and rules, keep the rule ids unique across the estate (a prefix per site: ABP-SB- for these two), and give each rule the check that enforces it, or say plainly that nothing does."
}
