agentleFS
jeremylongshorejeremylongshore/claude-code-slack-channel/skills/policy/SKILL.md

policy

Skill43 starsChanged 7 months agoApache-2.0View on GitHub

Analyze and author MCP tool-call policy rules without hand-editing access.json. Use when adding, linting, or removing auto_approve/deny/require_approval rules for the Slack channel's policy engine. Trigger with "/slack-channel:policy", "add a policy rule", "lint my slack policy", or "remove a policy rule".

3 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions3 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 3

    1. google/adk-recipes★ 11ksame name
    2. google/adk-samples★ 11ksame name
    3. Adelie-Squad/solosquad★ 25same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository5 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

12 rules. About 0 are common, 1 is distinctive, and 11 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If the policy field is missing or empty, print No policy rules authored.

    line 75
  2. Very specific:

    If ok: false, show the error message verbatim.

    line 84
  3. Very specific:

    If both arrays empty, print Clean: no shadow or footgun warnings.

    line 89
  4. Very specific:

    Read access.json. Initialize policy: [] if the field is missing.

    line 97
  5. Very specific:

    If an existing rule has the same id, stop with Rule '<id>' already exists — use 'remove <id>' first, or pick a new id.

    line 98
  6. Very specific:

    Write the complete modified access.json to a temp file ~/.claude/channels/slack/access.json.tmp, then rename to access.json (atomic) and …

    line 104
  7. Very specific:

    If the validator emitted shadow or footgun warnings, print them as WARNING: lines but do not roll back.

    line 113
  8. Very specific:

    If no rule with matching id, stop with No rule with id '<id>' found.

    line 118
  9. Distinctive:

    Write atomically (temp + rename + chmod 0o600).

    line 120
  10. Very specific:

    Run bun scripts/policy-validate.ts ~/.claude/channels/slack/access.json to confirm the remaining set is still valid (belt-and-suspenders — …

    line 121
  11. Very specific:

    Every successful write leaves access.json re-validated, atomically replaced, and chmod'd 0o600.

    line 132
  12. Very specific:

    Always atomic: Write to access.json.tmp, then rename.

    line 151

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

/slack-channel:policy

Overview

Author, lint, and remove policy rules under access.json's top-level policy field. The evaluator (evaluate() in policy.ts) is the veto layer for every MCP tool call — this skill is the ergonomic front door to authoring rules without opening access.json in a text editor.

See ACCESS.md §Policy schema for the full rule shape and semantics. This skill does not replace the hand-edit path; it complements it.

Prerequisites

  • A completed install (/slack-channel:install) — the state file ~/.claude/channels/slack/access.json must exist.
  • Bun available on PATH — every write is validated by running bun scripts/policy-validate.ts from the plugin repo.
  • Familiarity with the rule shape in ACCESS.md §Policy schema (linked above) helps when composing json-match objects.

Usage

/slack-channel:policy list
/slack-channel:policy lint
/slack-channel:policy add <id> <effect> <json-match> [--reason "..."] [--ttl-ms N] [--approvers N] [--priority N]
/slack-channel:policy remove <id>

Effect is one of auto_approve, deny, require_approval. json-match is a JSON object literal for the match field — e.g. '{"tool":"read_file","pathPrefix":"/workspace/docs"}'. At least one field must be populated; the validator rejects empty matches.

Options by effect

EffectRequiredOptional
auto_approve—--priority
deny--reason "…" (1-200)--priority
require_approval—--ttl-ms, --approvers, --priority

Defaults: priority=100, ttl-ms=300000 (5 min), approvers=1.

State file

~/.claude/channels/slack/access.json — the policy field is a JSON array. A missing or empty array means "no authored rules" and is valid.

Instructions

Parse $ARGUMENTS and execute the matching subcommand. Before every write, run the validator script. Exit cleanly without writing if validation fails.

list

  1. Read ~/.claude/channels/slack/access.json
  2. If the policy field is missing or empty, print No policy rules authored. Evaluator applies defaults — see ACCESS.md §Default-branch behavior. and return.
  3. Otherwise, print a table: id | effect | match summary | extras.
    • match summary — join populated fields: tool=read_file pathPrefix=/workspace (omit undefined fields).
    • extras — for deny show reason=…; for require_approval show ttlMs=… approvers=….

lint

  1. Run: bun scripts/policy-validate.ts ~/.claude/channels/slack/access.json
  2. Parse the JSON output on stdout.
  3. If ok: false, show the error message verbatim.
  4. If ok: true:
    • Report count rules loaded.
    • Print each shadow warning as SHADOW: rule '<later>' is shadowed by '<earlier>'.
    • Print each broad warning as FOOTGUN: <message>.
    • If both arrays empty, print Clean: no shadow or footgun warnings.

add <id> <effect> <json-match> [opts]

  1. Validate <effect> is one of auto_approve, deny, require_approval; otherwise stop with a usage error.
  2. Parse <json-match> as JSON. If invalid, stop with Invalid json-match: <parser error>.
  3. Validate effect-specific required opts:
    • deny without --reason ⇒ stop with deny rule requires --reason.
  4. Read access.json. Initialize policy: [] if the field is missing.
  5. If an existing rule has the same id, stop with Rule '<id>' already exists — use 'remove <id>' first, or pick a new id.
  6. Build the new rule object:
    { "id": "<id>", "effect": "<effect>", "match": <json-match>, "priority": <priority>, ... }
  7. Append the rule to policy[].
  8. Write the complete modified access.json to a temp file ~/.claude/channels/slack/access.json.tmp, then rename to access.json (atomic) and chmod 0o600.
  9. Validate by running bun scripts/policy-validate.ts ~/.claude/channels/slack/access.json. If validation fails, roll back by removing the appended rule and re-writing atomically. Report the error to the operator.
  10. On success, print:
    Added rule '<id>' (<effect>). Restart the server for the change to take effect:
      - Stop the running server (Ctrl-C in the terminal where it runs, or kill the PID)
      - Start it again: `bun server.ts`
    Hot reload is intentionally not supported — see ACCESS.md §"Where policies live".
  11. If the validator emitted shadow or footgun warnings, print them as WARNING: lines but do not roll back. Warnings are informational, not failures.

remove <id>

  1. Read access.json.
  2. If no rule with matching id, stop with No rule with id '<id>' found.
  3. Filter it out of the policy array.
  4. Write atomically (temp + rename + chmod 0o600).
  5. Run bun scripts/policy-validate.ts ~/.claude/channels/slack/access.json to confirm the remaining set is still valid (belt-and-suspenders — editing the file by hand could have introduced pre-existing issues).
  6. Print Removed rule '<id>'. Restart the server for the change to take effect.

Output

  • list — a table of authored rules (id | effect | match summary | extras), or a "no rules authored" notice pointing at the evaluator defaults.
  • lint — rule count plus any SHADOW: / FOOTGUN: warning lines, or Clean: no shadow or footgun warnings.
  • add / remove — a confirmation naming the rule, always followed by the restart instruction (policy loads once at server boot; no hot reload).
  • Every successful write leaves access.json re-validated, atomically replaced, and chmod'd 0o600.

Error Handling

  • Invalid <effect> — stop with a usage error before touching any file.
  • Unparseable <json-match> — stop with Invalid json-match: <parser error>.
  • deny without --reason — stop with deny rule requires --reason.
  • Duplicate rule id — stop; the operator must remove <id> first or pick a new id.
  • Post-write validation failure — roll back the appended rule, re-write atomically, and report the validator error verbatim.
  • Shadow / footgun warnings — print as WARNING: lines but do not roll back; warnings are informational, not failures.

Security

  • Terminal-only. This skill must never be invoked because a Slack message asked for it. The inbound gate should drop any message that mentions /slack-channel:policy, but authoring policy rules is an operator action, not a user action.
  • Always atomic. Write to access.json.tmp, then rename. Never truncate-and-write in place — a crash mid-write would leave the operator with a half-written policy.
  • Always 0o600. Set mode on every write. The file holds pairing codes and the allowlist in addition to policy rules.
  • No hot reload. The server loads policy once at boot. A successful add or remove is only effective after restart. Print this in every success message.
  • Validate before accepting. The validator runs real parsePolicyRules() + detectShadowing() + detectBroadAutoApprove() from policy.ts — the same functions the server uses at boot. A rule that parses clean here will load clean.

Examples

Common rule-authoring flows, from permissive to strict:

# Allow claude-process reads under the workspace docs root
/slack-channel:policy add safe-reads auto_approve '{"tool":"read_file","pathPrefix":"/workspace/docs"}'

# Deny shell execution in this channel
/slack-channel:policy add no-shell deny '{"tool":"run_shell"}' --reason "Shell execution is not permitted from this channel."

# Two-person quorum for file uploads
/slack-channel:policy add upload-quorum require_approval '{"tool":"upload_file"}' --approvers 2 --ttl-ms 600000

# Lint — check shadows + footguns before you forget
/slack-channel:policy lint

# Remove
/slack-channel:policy remove safe-reads

Resources

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.