TFD-0016: Permission Policy — Factory & Shipped Digital Talents
TFD-0016: Permission Policy — Factory & Shipped Digital Talents
Status: Draft Date: 2026-05-12 Decision maker: CTO (Clara) + CEO (Oscar) Source: RD-0003 hack #30 + factory audit revealing
defaultMode: bypassPermissionsneutralizes the existing allow list
Context
The Talent Factory currently runs with the following permission posture:
.claude/settings.json(committed): defines hooks (terminology guard, Jira naming, AC/DoD enforcement), enables 3 plugins. Nopermissionsblock..claude/settings.local.json(local, gitignored): substantial allow + deny lists, but"defaultMode": "bypassPermissions"— which renders the allow list largely irrelevant: everything is allowed except what's indeny.
Shipped digital talents (DAE-NNNN in OneDrive-STM/agent-ea/, vah-payroll, future deliveries) inherit no standard permission template. Each client's environment runs with whatever the operator configured locally.
This contradicts the foundry delivery model (feedback_delivery-model-foundry-not-hosted): we ship talents that customers run autonomously, so the customer's safety depends on the policy we ship with the talent, not on whatever local override the operator picks.
RD-0003 hack #30 articulates the principle: speed comes from the number of permission prompts, not from bypassing the permission layer. An explicit allow + deny list gives the same throughput as bypassPermissions without the same blast radius.
Decisions
D1 — Factory Dev posture
Decision: Replace defaultMode: bypassPermissions with defaultMode: acceptEdits in factory .claude/settings.local.json.
The existing allow list already covers the tools we use daily. With acceptEdits (or default) instead of bypass, Claude prompts only on commands not in the allow list — which is the desired friction (catches new bash patterns the operator hasn't vetted).
The deny list stays. Anything destructive remains blocked regardless of allow list ordering.
Action — Ivan: edit C:\Projects\talent-factory\.claude\settings.local.json, set defaultMode to "acceptEdits". Operator can override per-session via CLI flags if a legitimate need arises.
D2 — Shipped digital talents posture
Decision: All shipped digital talents must include a permissions block in .claude/settings.json (committed) with the standard allow/deny template below.
.claude/settings.local.json remains gitignored and per-operator; the committed settings.json becomes the safety floor that travels with the talent.
Standard template — to add to talent template (production-lines/digital-talent/templates/):
{
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Read", "Write", "Edit", "Glob", "Grep",
"Bash(git status*)", "Bash(git log*)", "Bash(git diff*)", "Bash(git add*)", "Bash(git commit*)",
"Bash(ls*)", "Bash(cat*)", "Bash(head*)", "Bash(tail*)",
"Bash(python *)", "Bash(node *)", "Bash(npm run *)", "Bash(npx *)",
"WebFetch", "WebSearch",
"AskUserQuestion", "TaskCreate", "TaskUpdate", "TaskList", "TaskGet"
],
"deny": [
"Bash(git push --force*)", "Bash(git push -f*)",
"Bash(git reset --hard*)", "Bash(git clean -f*)", "Bash(git checkout -- .)",
"Bash(git branch -D*)",
"Bash(rm -rf /*)", "Bash(rm -rf ~*)", "Bash(rm -rf C:*)",
"Bash(sudo *)", "Bash(su *)", "Bash(runas *)",
"Bash(npm publish*)", "Bash(pip uninstall*)",
"Bash(kubectl delete*)", "Bash(docker system prune*)",
"Read(*.env)", "Read(*credentials*)", "Read(*secret*)", "Read(*.pem)"
]
}
}
Per-talent allow extensions go additive (e.g., DXF cadenassage talent adds Bash(ezdxf*)). Deny list is the universal floor — talents may add to it, never remove.
Deny prime sur allow is the Claude Code default — no special config needed for that.
Action — Pablo + Ivan: create production-lines/digital-talent/templates/permissions-template.json and wire into Stage 6 deployment checklist (06-deployment.md) as a required artifact.
D3 — Retroactive application to deployed talents
Decision: Apply the D2 template to all shipped talents (DAE-0001..0007, vah-payroll-2) as part of their next maintenance window or before the next handover, whichever comes first.
Not a blocker for current STM revenue (project_production-line-strategy — handover #1). Apply opportunistically.
Action — Max (Maintenance): track in factory-backlog as separate CI per talent. Schedule against handover cadence.
D4 — Agent Teams flag
Out of scope but flagged: .claude/settings.json factory currently has "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" in env. This contradicts feedback_no-agent-teams (MEMORY) which explicitly forbids agent teams in factory workflows.
Action — Clara: review whether this flag should be removed. Separate CI item (see CI-0034).
Rationale
Three forces converge:
- Foundry delivery model — customers run our talents independently; we own the safety floor we ship with.
- Hack #30 evidence — allow/deny matches
--dangerously-skipspeed in practice without the blast radius. - Existing partial implementation — factory already has 90% of the pieces; the missing 10% (defaultMode, committed template, talent rollout) is low-effort, high-trust-gain.
Non-decisions (parked)
- Per-client allow extensions (e.g., STM-specific commands): parked until a real client request triggers it. Default = no client-specific extensions.
- Hook-level confirmation for high-stakes commands (npm publish, etc.): considered, deferred —
denyis sufficient for now.