Agent skill

Arandu Policy and Grants

by arandu-io in arandu-io/arandu

Explains authorization in an Arandu Go application: write a Policy, get a security.Grant through security.Authorize, re-authorize each row, and keep tenant isolation.

MITAuto-check passedBackend & APIs

Install Arandu Policy and Grants

skills CLI
$ npx skills add arandu-io/arandu --skill arandu-policy -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install arandu-io/arandu arandu-policy --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/arandu-io/arandu.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/arandu-policy .claude/skills/arandu-policy && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
arandu-policy
GitHub stars
281
Token cost
~1.9k tokens
SKILL.md length
813 words
Files
1
Skills in repo
12
Repo updated
First seen
Licence
MIT

At a glance

Explains authorization in an Arandu Go application: write a Policy, get a security.Grant through security.Authorize, re-authorize each row, and keep tenant isolation.

  • Works in 5 steps: Name the action as a constant in the… → Decide in Can, inside the custom block:… → Ask from the service, twice for one row.… → …
  • Writing or changing who may read or change a record in an Arandu app
  • SKILL.md covers When to use, Before you start, Contracts and imports and Procedure, plus 8 more sections
  • Calls go and bash

What it does

In Arandu, security.Grant has only unexported fields, so code outside its package cannot build one, and every Model read or write requires one: the query terminals First, Get and Value, and an entity's Save and Delete. A service that never asks a Policy has nothing to pass, so unauthorized access fails to compile. The tenant is read from the grant with data.Tenant, never from the path, body or a header. The skill warns against deleting the grant parameter just to make code compile, since that parameter is what keeps the query safe.

The procedure is that a Policy implements Can, returning nil to allow and an error to deny, with actions as constants, tenant isolation checked first and no default branch that allows. A service calls security.Authorize with the policy, subject, action and resource, and only a nil result yields the Grant. After loading a record it authorizes the row as well, since otherwise any user in the tenant can see it and aru doctor reports resource-not-reauthorized, and writes check the stored row rather than what the request claims. Reads such as List, Find, projections, reports and exports need a Grant too, and SystemGrant is covered as well.

When your agent uses it

  • Writing or changing who may read or change a record in an Arandu app
  • Fixing a compile error that asks for a security.Grant
  • Adding tenant isolation to a new service or Model query
  • Writing a Policy for a new resource

Example prompts

  • “Add a Policy so only an invoice's owner can update it, and wire it into the service.”
  • “InvoiceService.Get will not compile without a Grant. What should I do?”
  • “Make sure this report endpoint is tenant-isolated and re-authorizes each row.”

Requirements

  • An Arandu Go project

Workflow steps

5 steps, taken from the first numbered list in SKILL.md.

  1. Name the action as a constant in the policy's file, beside the five
  2. Decide in Can, inside the custom block: tenant isolation first, the
  3. Ask from the service, twice for one row. Once with the zero value, to
  4. Read and write with the Grant that came back. Reads are not exempt: a
  5. For work with nobody asking, use auth.SystemGrant in a seeder, a job, a

What it can do on your machine

Read from SKILL.md and the folder at commit b8a4273. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • go
    • bash

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Arandu Policy and Grants loads about 1.9k tokens when it runs. Until then it costs about 154 tokens; SKILL.md has 813 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~154
When it runs · the whole SKILL.md, loaded when a task matches
~1.9k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from arandu-io/arandu at commit b8a4273, republished under its MIT licence (© arandu-io). 813 words, ~1,904 tokens.

Download SKILL.mdSave it as .claude/skills/arandu-policy/SKILL.md (or your agent's skills folder).
name
arandu-policy
description
Authorization in an Arandu (Go) application. Use when writing or changing who may read or change a record, when a Model or service call will not compile, when something asks for an auth.Grant, or when the request mentions "permissions", "roles", "who can access", "only the author", "authorize", "multi-tenant", "tenant isolation", or "this method needs a Grant". Also use when tempted to remove a parameter to make code compile -- here that parameter is the only thing making the query safe. Covers Policy, Grant, auth.Authorize, auth.Tenant, re-authorizing the row, SystemGrant and aru make:policy.
license
MIT

Authorization, and why it will not compile without it

When to use

Who may take an action on a record, the tenant a query reads, a Grant a call asks for, and the one escape hatch for work with nobody asking. Which roles a member holds inside an organization is arandu-ecosystem (arandu-permission); this skill is the decision about a record.

Before you start

  • Read app/Policies/NotePolicy.go, the example's rules, and the Get and Publish methods of app/Services/NoteService.go, which ask it.
  • auth.Grant has only unexported fields: nothing outside its package builds one. Every read and write through a model takes one. A service that reaches the database without asking a Policy has nothing to pass, and does not compile. The safe path is not documented; the unsafe path is absent.

Contracts and imports

All from github.com/arandu-io/hesape/auth:

symbolcontract
Actiona named constant, entity first: NoteView auth.Action = "note.view"
Policy[T]Can(ctx, s auth.Subject, a auth.Action, x T) error: nil allows, an error denies; it never builds a Grant
Authorizeauth.Authorize(ctx, policy, subject, action, resource) (auth.Grant, error): runs Can, and only when it answers nil issues the Grant
Grantwhat every terminal of a generated query, Save and Delete take; g.Check(action) asks whether it was issued for an action
Tenantauth.Tenant(g), the only source of a tenant
SystemGrantauth.SystemGrant(action, tenant), for work with no subject: a seeder, a job, a command, main.go
Subjectwho is asking: ID, Tenant, Roles, HasRole

Procedure

  1. Name the action as a constant in the policy's file, beside the five the generator writes -- the example added NotePublish.
  2. Decide in Can, inside the custom block: tenant isolation first, the zero subject refused, then one case per action, and nothing that allows by default -- the function denies by falling through.
  3. Ask from the service, twice for one row. Once with the zero value, to ask "may this caller look at all", and once with the row in hand, "may this caller look at this row". A write asks about the row it read, never about what the request says the row is, so NoteService.Publish authorizes NotePublish against the stored note and its stored author.
  4. Read and write with the Grant that came back. Reads are not exempt: a list, a report, an export and a projection all take a Grant and filter by its tenant.
  5. For work with nobody asking, use auth.SystemGrant in a seeder, a job, a command or main.go. Anywhere else it carries its reason on the line before: //arandu:system-grant <reason>, as the example's listener does.

Commands

  • aru make:policy <module> writes a policy that denies every action
  • aru make:module writes one with the module
  • aru action:list lists the actions the source declares, with the constant and the line of each

Example

A rule about the row, and the double authorization that reads it:

go
package example

import (
	"context"
	"fmt"

	"github.com/arandu-io/hesape/auth"
	"github.com/arandu-io/hesape/database"

	models "<module>/app/Models"
)

// NotePin is pinning one note.
const NotePin auth.Action = "note.pin"

// PinPolicy decides who pins a note: its author, in its tenant.
type PinPolicy struct{}

var _ auth.Policy[models.Note] = PinPolicy{}

// Can answers nil to allow and an error to deny, and denies by falling through.
func (PinPolicy) Can(_ context.Context, s auth.Subject, a auth.Action, n models.Note) error {
	if n.ID != "" && n.TenantID != s.Tenant {
		return fmt.Errorf("note belongs to another tenant")
	}
	if s.ID == "" || s.Tenant == "" {
		return fmt.Errorf("pinning needs somebody signed in")
	}
	if a == NotePin && (n.ID == "" || n.OwnedBy(s.ID)) {
		return nil
	}
	return fmt.Errorf("no rule allows %s on note", a)
}

// Pin reads the row through a Grant, authorizes the row it read, and writes
// with the Grant that decision issued.
func Pin(ctx context.Context, db *database.DB, actor auth.Subject, id string) error {
	g, err := auth.Authorize(ctx, PinPolicy{}, actor, NotePin, models.Note{})
	if err != nil {
		return err
	}
	note, err := models.Notes(db).FindOrFail(ctx, g, id)
	if err != nil {
		return err
	}
	g, err = auth.Authorize(ctx, PinPolicy{}, actor, NotePin, *note)
	if err != nil {
		return err
	}
	note.Pinned = true
	_, err = note.Save(ctx, g)
	return err
}
Show full SKILL.md (350 more words)Show less

Do not

  • Remove a Grant parameter to make something compile. There is no correct way to query a model without one.
  • Read the tenant from a path, a body, a query string or a header: tenant-from-request, tenant-from-header. It is auth.Tenant(g).
  • Authorize in middleware, or in the controller. A guard answers "is there a session" and stops; the policy runs in the service, for every caller of it.
  • Skip the second authorization on a row you read: resource-not-reauthorized.
  • Answer another tenant's row with 403. A guessed id is not found -- a 403 confirms the row exists -- and the tenant scope of every query already makes it so.
  • Add a role column, an is_admin flag or an ACL table: roles are arandu-permission's (arandu-ecosystem), and the policy reads them off the subject.

Extending it

A rule goes in the custom block of Can; an action is a constant beside the generated ones. A rule that depends on another record -- the note a comment belongs to -- is decided by loading that record through its own service and policy, as CommentService loads the note, never by reading its table here.

Wiring

A policy is a value: the service holds it as a field and passes it to auth.Authorize. Nothing registers it, and nothing in bootstrap/app.go changes.

Acceptance test

  • A unit test that an action nobody wrote a rule for is refused, which the generator writes and keeps passing as the policy opens.
  • A unit test that every read of the service is refused for the zero subject before the database is touched -- the service runs with a nil database.
  • Feature tests: another member's change answered 403, another tenant's row 404, for every action that takes an id.

Limits

SystemGrant exists. What catches a handler using it is aru doctor (system-grant-outside-scope), not the type system, and the marker excuses the line it is on and nothing else. A table with no tenant column is invisible to the tenant test, and its isolation rests on every query of it taking a Grant.

Gates

Run them all, in this order, as AGENTS.md lists them:

sh
export GOWORK=off
aru model:build --check
aru view:build
gofmt -l $(find . -name '*.go' -not -path '*/testdata/*' -not -name '*.kyse.go')
go vet ./...
bash tests/test-layout-guard.sh
go test -race ./...
go build ./...
aru doctor
<!-- arandu:begin custom -->
<!-- arandu:end custom -->

© arandu-io, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/arandu-policy of arandu-io/arandu.

Open the folder on GitHubat commit b8a4273

Compare with similar skills

Arandu Policy and Grants next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Arandu Policy and Grants compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Arandu Policy and Grants this skillarandu-io/arandu281—~1.9kAutomated safety check: PassMIT
Django Access Reviewgetsentry/skills1k3 repos~2.6kAutomated safety check: NotesApache-2.0
Cb Security HardeningBlkLeg/CircuitBreaker201—~2.1kAutomated safety check: PassMIT
Openfdd Mt Securitybbartling/open-fdd173—~2.2kAutomated safety check: PassCustom licence
Abp Authorizationabpframework/abp14k—~1.3kAutomated safety check: PassLGPL-3.0
Security Review ChecklistZeroDeng01/sublinkPro1.7k—~2.3kAutomated safety check: PassMIT

Similar skills

  • Django Access Review

    getsentry/skills

    Official

    Django access control and IDOR security review. An agent skill from getsentry/skills.

    1k GitHub starsUsed in 3 repos~2.6k tokens
    Backend & APIsAuto-check: notes
  • Cb Security Hardening

    BlkLeg/CircuitBreaker

    Enforces Circuit Breaker security hardening conventions across backend, frontend, Docker, and nginx.

    201 GitHub stars~2.1k tokensUpdated 5 days ago
    Backend & APIsAuto-check passed
  • Openfdd Mt Security

    bbartling/open-fdd

    Multi-tenant authz, pre-auth disclosure hardening, and Kali disposition.

    173 GitHub stars~2.2k tokensUpdated today
    Backend & APIsAuto-check passed
  • Abp Authorization

    abpframework/abp

    ABP permission system - PermissionDefinitionProvider, [Authorize] attribute, CheckPolicyAsync, IsGrantedAsync, ICurrentUser, IPermissionManager, multi-tenancy side.

    14k GitHub stars~1.3k tokensUpdated yesterday
    Backend & APIsAuto-check passed
  • Security Review Checklist

    ZeroDeng01/sublinkPro

    Checklist-driven security review for changes to authentication, authorization, MFA, secrets, input validation and other security-critical code.

    1.7k GitHub stars~2.3k tokensUpdated 2 days ago
    SecurityAuto-check passed
  • Supercheck Security Auth

    supercheck-io/supercheck

    Work on Supercheck authentication, RBAC, tenant isolation, sessions, API and trigger keys, invitations, project membership, project variables, OAuth, super-admin behavior, SSRF, or…

    215 GitHub stars~1.2k tokensUpdated today
    Backend & APIsAuto-check passed

More from arandu-io/arandu

All 12 skills in this repo
  • Arandu API

    arandu-io/arandu

    Answering a program rather than a person in an Arandu (Go) application -- a JSON Resource, a JSON answer from the same routes the pages use, problem+json errors, bearer-token authentication and…

    281 GitHub stars~2.5k tokensUpdated yesterday
    Auto-check passed
  • Arandu Async

    arandu-io/arandu

    Work that does not happen inside the request in an Arandu (Go) application -- background jobs and the worker, scheduled tasks, domain events through the outbox, listeners, notifications, mail and…

    281 GitHub stars~2.7k tokensUpdated yesterday
    Auto-check passed
  • Decides whether a feature belongs in the application or in one of five shared Arandu modules before adding permissions, wallets, tags, Markdown rendering or API docs.

    281 GitHub stars~1.8k tokensUpdated yesterday
    Auto-check passed
  • Arandu Feature

    arandu-io/arandu

    Start here for any change to an Arandu (Go) application that adds or changes behaviour -- "add invoices", "let users publish a post", "send a weekly report", "call the payment provider", "expose…

    281 GitHub stars~2.5k tokensUpdated yesterday
    Auto-check passed
  • Arandu HTTP

    arandu-io/arandu

    Controllers, requests and routes of an Arandu (Go) application -- the seven resource actions, a resource nested under another, a singleton, a single-action (invokable) controller, a named action…

    281 GitHub stars~2.5k tokensUpdated yesterday
    Auto-check passed
  • Arandu Integrations

    arandu-io/arandu

    Reaching other systems from an Arandu (Go) application, and letting them reach it -- the client of an external API with its interface and fake, webhooks sent and received, and tools, resources and…

    281 GitHub stars~3.1k tokensUpdated yesterday
    Auto-check passed

Works with

Questions about Arandu Policy and Grants

What does Arandu Policy and Grants do?

Explains authorization in an Arandu Go application: write a Policy, get a security.Grant through security.Authorize, re-authorize each row, and keep tenant isolation. Grant has only unexported fields, so code outside its package cannot build one, and every Model read or write requires one: the query terminals First, Get and Value, and an entity's Save and Delete. A service that never asks a Policy has nothing to pass, so unauthorized access fails to compile.

When should I use Arandu Policy and Grants?

Arandu Policy and Grants fits situations like: writing or changing who may read or change a record in an Arandu app; fixing a compile error that asks for a security.Grant; adding tenant isolation to a new service or Model query; writing a Policy for a new resource.

How do I install Arandu Policy and Grants in Claude Code?

Run `npx skills add arandu-io/arandu --skill arandu-policy -a claude-code`. Or copy the skill folder (.agents/skills/arandu-policy in arandu-io/arandu) into .claude/skills/arandu-policy in your project. Claude Code loads it when a task matches its description.

How do I install Arandu Policy and Grants in Codex?

Run `npx skills add arandu-io/arandu --skill arandu-policy -a codex`. Or copy the skill folder (.agents/skills/arandu-policy in arandu-io/arandu) into .agents/skills/arandu-policy in your project. Codex loads it when a task matches its description.

Can I use Arandu Policy and Grants in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add arandu-io/arandu --skill arandu-policy -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/arandu-policy, .gemini/skills/arandu-policy, .github/skills/arandu-policy and .opencode/skills/arandu-policy in your project.

What does Arandu Policy and Grants need to run?

Going by SKILL.md and its folder, Arandu Policy and Grants needs the command-line tools its instructions call (go and bash). Our summary lists: An Arandu Go project.

Does Arandu Policy and Grants access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Arandu Policy and Grants safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Arandu Policy and Grants use?

Arandu Policy and Grants is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Arandu Policy and Grants use?

About 1.9k tokens (SKILL.md is roughly 7.6k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Arandu Policy and Grants?

Skills that share tags, products or a category with Arandu Policy and Grants: Django Access Review (getsentry/skills, 1k stars), Cb Security Hardening (BlkLeg/CircuitBreaker, 201 stars), Openfdd Mt Security (bbartling/open-fdd, 173 stars) and Abp Authorization (abpframework/abp, 14k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Arandu Policy and Grants?

arandu-io (a GitHub organization) maintains it in arandu-io/arandu, which has 281 GitHub stars. The repository holds 12 skills in this directory. The repository was last updated on October 10, 2026.

Source: arandu-io/arandu on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.