Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
167 changes: 167 additions & 0 deletions .agents/skills/openfga/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
name: openfga
description: OpenFGA authorization modeling best practices for defining types and relations, writing relationship tuples, deriving can_* permissions, applying type restrictions and usersets, and authoring .fga.yaml check/list_objects/list_users tests. Use when authoring, reviewing, or refactoring OpenFGA models, tuples, permissions, .fga files, .fga.yaml test files, or OpenFGA SDK integrations in JavaScript, TypeScript, Go, Python, Java, or .NET.
license: Apache-2.0
metadata:
author: openfga
version: "1.2.1"
---

# OpenFGA Best Practices

Use this skill to design and review OpenFGA models end to end: define types and relations, write tuples, derive `can_*` permissions, choose usersets and inheritance patterns, and validate behavior with `.fga.yaml` tests and CLI checks.

## Quick Start Example

Minimal model:

```fga
model
schema 1.1

type user

type organization
relations
define admin: [user]
define member: [user] or admin

type document
relations
define organization: [organization]
define owner: [user]
define can_edit: owner or admin from organization
define can_view: can_edit or member from organization
```

Example tuples:

```text
organization:acme#admin@user:alice
document:roadmap#organization@organization:acme
document:roadmap#owner@user:bob
```

Example test targets:
- `check` that `user:alice` can view and edit `document:roadmap`
- `check` that `user:bob` can edit their own document
- `list_users` for `document:roadmap#can_view`
- `list_objects` for documents `user:alice` can edit

## How to Use

When a workflow step points to a rule ID, open the matching file in `references/` for detailed guidance and examples.

**Note:** SDK references (`sdk-*.md`) are only needed for integration tasks — skip them during pure model authoring and testing.

## Rule Index

### Core
| File | Description |
|------|-------------|
| `references/core-types.md` | Define types for entity classes |
| `references/core-relations.md` | Relations belong on object types |
| `references/core-tuples.md` | Relationship tuples as facts |
| `references/core-separation.md` | Model vs data separation |
| `references/core-schema-version.md` | Schema version |

### Relations
| File | Description |
|------|-------------|
| `references/relation-direct.md` | Direct relationships |
| `references/relation-indirect.md` | Indirect relationships with X from Y |
| `references/relation-concentric.md` | Concentric relationships |
| `references/relation-usersets.md` | Usersets for group-based access |
| `references/relation-conditions.md` | Conditional relationships |
| `references/relation-wildcards.md` | Wildcards for public access |
| `references/relation-wildcards-as-booleans.md` | Wildcards for boolean attributes |

### Design
| File | Description |
|------|-------------|
| `references/design-permissions.md` | Define permissions with can_ relations |
| `references/design-hierarchy.md` | Hierarchical structures |
| `references/design-organization.md` | Organization-level access |
| `references/design-create-on-parent.md` | Check create permissions on parent objects |
| `references/design-naming.md` | Naming conventions |
| `references/design-modules.md` | Modularize models (only when asked) |

### Roles
| File | Description |
|------|-------------|
| `references/roles-simple.md` | Simple static roles |
| `references/roles-static-combo.md` | Combining static and custom roles |
| `references/roles-assignments.md` | Role assignments for resource-specific roles |
| `references/roles-when-to-use.md` | When to use each role pattern |

### Optimization
| File | Description |
|------|-------------|
| `references/optimize-simplify.md` | Simplify models |
| `references/optimize-tuples.md` | Minimize tuple count |
| `references/optimize-type-restrictions.md` | Type restrictions |

### Testing
| File | Description |
|------|-------------|
| `references/test-fga-yaml.md` | Structure tests in .fga.yaml |
| `references/test-check-assertions.md` | Check assertions |
| `references/test-list-objects.md` | List objects tests |
| `references/test-list-users.md` | List users tests |
| `references/test-conditions.md` | Testing conditions |
| `references/test-cli.md` | OpenFGA CLI usage |
| `references/workflow-validate.md` | Always validate models |

### SDKs (for integration tasks only)
| File | Description |
Comment on lines +59 to +116

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Resolve the reported Markdown lint and labeling defects.

  • .agents/skills/openfga/SKILL.md#L59-L116: add blank lines around the rule-index headings and tables.
  • .agents/skills/openfga/SKILL.md#L152-L161: use the configured ordered-list prefix style.
  • .agents/skills/openfga/references/relation-concentric.md#L83-L83: label the fenced diagram as text.
  • .agents/skills/openfga/references/relation-wildcards-as-booleans.md#L5-L22: rename the heading to match the boolean-attribute topic and change **Tuples ** to **Tuples**.
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 59-59: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 60-60: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 68-68: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 69-69: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 79-79: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 80-80: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 89-89: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 90-90: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 97-97: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 98-98: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 104-104: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 105-105: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


[warning] 115-115: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 116-116: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

📍 Affects 3 files
  • .agents/skills/openfga/SKILL.md#L59-L116 (this comment)
  • .agents/skills/openfga/SKILL.md#L152-L161
  • .agents/skills/openfga/references/relation-concentric.md#L83-L83
  • .agents/skills/openfga/references/relation-wildcards-as-booleans.md#L5-L22
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/skills/openfga/SKILL.md around lines 59 - 116, Resolve the Markdown
lint issues across the listed sites: in .agents/skills/openfga/SKILL.md lines
59-116, add blank lines around each rule-index heading and table; in
.agents/skills/openfga/SKILL.md lines 152-161, change the ordered list to the
configured prefix style; in
.agents/skills/openfga/references/relation-concentric.md line 83, label the
fenced diagram as text; and in
.agents/skills/openfga/references/relation-wildcards-as-booleans.md lines 5-22,
rename the heading to reflect boolean attributes and remove the extra space in
the bold Tuples label.

Source: Linters/SAST tools

|------|-------------|
| `references/sdk-javascript.md` | JavaScript/TypeScript SDK |
| `references/sdk-go.md` | Go SDK |
| `references/sdk-python.md` | Python SDK |
| `references/sdk-java.md` | Java SDK |
| `references/sdk-dotnet.md` | .NET SDK |

## Recommended Workflow

1. Model the resource graph.
Define types, direct relations, inheritance edges, and `can_*` permissions.
Rules to check first: `core-*`, `relation-*`, `design-permissions`, `design-hierarchy`.

2. Add tuples and test intent.
Add representative tuples and cover expected behavior with `check`, `list_objects`, and `list_users` tests.
Rules to check next: `core-tuples`, `test-fga-yaml`, `test-check-assertions`, `test-list-objects`, `test-list-users`.

3. Review parent-child creation and deletion paths.
Verify each parent -> child edge has create permissions on the parent and that no child permission is directly grantable unless intended.
Rules to check: `design-create-on-parent`, `relation-direct`, `design-permissions`.

4. Simplify before removing schema.
Before deleting any type or relation, confirm it is not referenced by permissions, tuples, or tests.
If a simplification breaks a reference: restore the relation or update the model/tests, then re-run this step.
Rules to check: `optimize-simplify`, `optimize-tuples`, `optimize-type-restrictions`.

5. Validate the model.
Run:

```bash
fga model validate --file stores/<store>/model.fga
```

If validation fails: read the reported relation or type errors, fix the model, and re-run validation before continuing.

6. Run the store tests.
Run:

```bash
fga model test --tests stores/<store>/store.fga.yaml
```

If tests fail: update tuples, assertions, or permission definitions, then re-run tests until all checks and list queries pass.
Comment on lines +143 to +159

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
git ls-files | rg '(^|/)(SKILL\.md|store\.fga\.yaml|model\.fga|README|package\.json|pyproject\.toml|justfile|Makefile)$' | sed -n '1,200p'

echo
echo "== SKILL.md around target lines =="
if [ -f .agents/skills/openfga/SKILL.md ]; then
  nl -ba .agents/skills/openfga/SKILL.md | sed -n '120,175p'
else
  fd -a 'SKILL\.md$' .agents/skills/openfga -x sh -c 'echo "--- $1"; nl -ba "$1" | sed -n "120,175p"' sh {}
fi

echo
echo "== openfga fixture files =="
git ls-files | rg 'openfga|authorization-openfga' | sed -n '1,200p'
if [ -f integrations/authorization-openfga/src/test/openfga/store.fga.yaml ]; then
  echo
  echo "== fixture contents =="
  nl -ba integrations/authorization-openfga/src/test/openfga/store.fga.yaml | sed -n '1,160p'
fi

echo
echo "== references to stores/ and model commands =="
rg -n '\bstores/|--file=model\.fga|--tests=|--tests|\bopenfga|\bFGA|authorization-openfga' .agents/skills integrations/authorization-openfga README.md 2>/dev/null || true

echo
echo "== static path validation for yaml refs =="
python3 - <<'PY'
from pathlib import Path
p=Path('integrations/authorization-openfga/src/test/openfga/store.fga.yaml')
if p.exists():
    text=p.read_text()
    print('exists:', p)
    for i,line in enumerate(text.splitlines(),1):
        if 'stores/' in line or 'model.fga' in line or 'fga' in line:
            print(f'{i}: {line}')
PY

Repository: kl3inIT/OrgMemory

Length of output: 1804


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== SKILL.md around target lines =="
python3 - <<'PY'
from pathlib import Path
p = Path('.agents/skills/openfga/SKILL.md')
lines = p.read_text().splitlines()
for i in range(120, min(180, len(lines)) + 1):
    print(f'{i}: {lines[i-1]}')
PY

echo
echo "== fixture contents =="
python3 - <<'PY'
from pathlib import Path
p = Path('integrations/authorization-openfga/src/test/openfga/store.fga.yaml')
for i, line in enumerate(p.read_text().splitlines(), 1):
    print(f'{i}: {line}')
PY

echo
echo "== model file exists check =="
python3 - <<'PY'
from pathlib import Path
for p in [
    Path('integrations/authorization-openfga/src/main/openfga/model.fga'),
    Path('integrations/authorization-openfga/src/test/openfga/model.fga'),
]:
    print(p, 'exists=', p.exists())
PY

Repository: kl3inIT/OrgMemory

Length of output: 21213


Make the OpenFGA commands use the repository layout.

The repository does not have a stores/<store>/model.fga path for this fixture. Update the workflow commands or provide explicit substitutions, using integrations/authorization-openfga/src/main/openfga/model.fga for validation and integrations/authorization-openfga/src/test/openfga/store.fga.yaml for tests.

🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 152-152: Ordered list item prefix
Expected: 1; Actual: 6; Style: 1/1/1

(MD029, ol-prefix)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/skills/openfga/SKILL.md around lines 143 - 159, Update the
validation and store-test commands in the workflow to use the repository fixture
paths: validate integrations/authorization-openfga/src/main/openfga/model.fga
and run tests with
integrations/authorization-openfga/src/test/openfga/store.fga.yaml. Remove the
incorrect stores/<store> path or replace it with explicit repository-specific
substitutions while preserving the existing failure-handling steps.

Source: Path instructions


7. Only then finalize delivery.
For touched stores, finish only after validation and tests are green.
Final rule to check: `workflow-validate`.

## Full Compiled Document

For the complete guide with all rules expanded: `AGENTS.md`
12 changes: 8 additions & 4 deletions .agents/skills/orgmemory-create-test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ Select the relevant layered gates from `docs/guidelines/testing-harness.md`.
For changes spanning ingestion, publication, persistence, worker wiring, or the
frontend contract, run at least:

```powershell
.\gradlew.bat --no-daemon :core:test :apps:api:test :apps:worker:test
.\gradlew.bat --no-daemon clean test
```bash
./gradlew --no-daemon :core:test :apps:api:test :apps:worker:test
./gradlew --no-daemon clean test
corepack pnpm --filter @orgmemory/web typecheck
corepack pnpm --filter @orgmemory/web test:unit
corepack pnpm --filter @orgmemory/web build
```

On native Windows replace `./gradlew` with `gradlew.bat`; the Corepack commands
are unchanged.

The terminating `clean test` command is the Spring context gate. Never use
`bootRun` as verification because it does not terminate on success.

Expand All @@ -44,7 +47,8 @@ When a REST endpoint or DTO changes, the committed contracts under
`apps/api/.../OpenApiContractTests.java`):

1. Refresh: set `ORGMEMORY_OPENAPI_WRITE=true` and run
`.\gradlew.bat :apps:api:test --tests "*OpenApiContractTests*"`.
`./gradlew :apps:api:test --tests '*OpenApiContractTests*'`.
On native Windows use `gradlew.bat` in place of `./gradlew`.
Comment on lines +50 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use shell-neutral quoting for the Gradle test filter.

The command uses single quotes around *OpenApiContractTests*. PowerShell removes those delimiters before invoking the batch file, but cmd.exe does not use single quotes as argument delimiters. The filter can reach Gradle with literal quote characters and match no tests. Use double quotes in the documented command. (learn.microsoft.com)

Proposed fix
-   `./gradlew :apps:api:test --tests '*OpenApiContractTests*'`.
+   `./gradlew :apps:api:test --tests "*OpenApiContractTests*"`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`./gradlew :apps:api:test --tests '*OpenApiContractTests*'`.
On native Windows use `gradlew.bat` in place of `./gradlew`.
`./gradlew :apps:api:test --tests "*OpenApiContractTests*"`.
On native Windows use `gradlew.bat` in place of `./gradlew`.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/skills/orgmemory-create-test/SKILL.md around lines 50 - 51, Update
the documented Gradle test command in the orgmemory-create-test skill to wrap
the *OpenApiContractTests* filter in double quotes instead of single quotes,
preserving the existing Unix and native Windows command variants.

2. Regenerate the browser client:
`corepack pnpm --filter @orgmemory/web gen:api` — the hey-api output is
gitignored, so it is regenerated, never committed.
Expand Down
Loading