Install
$ agentstack add skill-ashfulcra-fulcra-tools-fulcra-agent-roles ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Fulcra Agent Roles
Enhances the fulcra-agent-teams skill. A team's member//role.md says what a member does, but teams has no notion of a durable role that outlives any one session — "who is the reviewer right now?", "is anyone on-call?", "this role has been unattended too long." This skill adds that, as a pure OKF-markdown convention over the team namespace (lease mechanics via coord-engine roles verbs; everything else plain fulcra-api file + the OKF standard).
Where to start — the re-entrancy probes
Before claiming, escalating, or reading a role's status, probe where this role stands. Enter at the first probe that fails (per the repo's skill-quality pattern, docs/skill-quality-pattern.md); roles claim is a refresh, so re-entry is always safe:
| Probe (run in order) | Command | Passes when | If it fails, enter at | |---|---|---|---| | Role doc registered? | fulcra-api file download team//roles/.md - | prints a doc with type: Role (NON-mutating — do not probe registration via roles claim: claiming writes your lease before you've read the prior one, destroying same-id takeover evidence per "Role-as-identity" below) | Establish a role — write roles/.md (type: Role + policy/SLA/maintainer) | | Lease held by you? | coord-engine roles status | prints role in team/: HELD and your agent id is among the fresh holders: line | Claim / hold — run roles claim to write/refresh your lease shard | | Today's escalation clear? | fulcra-api file download team//roles//escalations/$(date -u +%Y-%m-%d).md - | download FAILS (no marker) — the role is not sitting escalated today | Escalate a vacancy — a marker present means a vacancy already fired today; drain it per "Escalate a vacancy" below |
All probes pass → the role is registered, you hold a fresh lease, and no vacancy escalation is outstanding for today; just re-claim on your cadence to keep the lease fresh.
Concepts
- Role — a named, durable function in the team (e.g.
reviewer,maintainer,on-call). Defined
once; sessions come and go.
- Lease — an agent's claim on a role, refreshed to prove liveness. A role is held while a fresh
lease exists.
- Policy —
shared(many holders allowed) orexclusive(one holder; a second fresh lease is a
contention signal).
- SLA / escalation — if a role sits vacant longer than
sla_hours, itsmaintaineris notified.
Layout (under team//roles/)
roles/.md— the role registry doc. OKFtype: Role. Created once when the role is
established. Frontmatter carries the policy and SLA: ```yaml --- type: Role title: Reviewer description: Adversarial code/plan review for the team's PRs. policy: shared # shared | exclusive sla_hours: 24 # vacancy longer than this escalates maintainer: ash # who gets the escalation (an agent or member name) --- # Duties
- Pick up review requests from the team inbox…
```
roles//leases/-.md— one lease per holder, named by the engine from the
holder's id (agent_key); never hand-name lease files. OKF type: Lease. The timestamp is the liveness signal — refresh it (re-claim) each time you act in the role: ``yaml --- type: Lease title: reviewer lease — treecle agent: treecle timestamp: 2026-07-01T18:00:00Z --- Holding the reviewer role. Next: drain the review inbox. ``
roles//escalations/.md— a first-writer-wins daily marker so a vacant role
escalates at most once per day (avoids spamming the maintainer).
Lifecycle
Establish a role (once)
Write roles/.md with type: Role + policy/SLA/maintainer — complete worked examples (exclusive maintainer, shared reviewer, shared multi-host monitor) are in [examples/](examples/). A roles/index.md is optional human courtesy: the engine folds role status from the directory listing, and the reference deployment does not maintain one.
Parking a role for a successor? The role doc is YOUR job, not theirs. A role can be claimed and worked without roles/.md ever being written — claim only warns — but the successor then inherits a role with broken review role-routing and status folds falling back to fabricated defaults (observed live 2026-07-22: a handed-off role was registered on the bus with no role doc, and the successor's claim landed on the warning). Before you park (see fulcra-agent-continuity, "Parking for a successor"), run the first re-entrancy probe above; if the doc is missing, write it — duties, policy, SLA, maintainer, and the checkpoint_ref your park will set — so the successor claims into a fully-routed role.
Claim / hold
coord-engine roles claim writes your lease shard (engine-named -.md; the command echoes the filename). Re-run it whenever you do work in the role — the refreshed timestamp is what keeps the role "held". Never hand-upload a lease file: a hand-named shard makes a SECOND lease for your id (spurious CONTESTED on exclusive roles). The Fulcra File Store versions every write, so the lease's history is an audit trail of your tenure.
Release
coord-engine roles release deletes your engine-named shard. (Deletion is intentional and not undoable — correct for releasing.)
Determine role status (the fold) — use the engine, do not eyeball timestamps
Classifying a role from many lease files is a fold over derived state: two agents must AGREE on whether a role is vacant before one escalates. Eyeballing timestamps drifts (the exact failure coord exists to prevent), so this is a deterministic coord-engine command, not a prose instruction:
coord-engine roles status --json
It reads the role's policy/sla_hours, folds the leases, and returns:
status— HELD (≥1 fresh lease) / VACANT (none) / DORMANT (vacant but deliberately parked, see "Park a role") / CONTESTED (exclusive+ ≥2 fresh) / UNKNOWN (unreadable),fresh_holders, andescalation_due(true iff vacant past SLA, not parked, and today's marker isn't present).
For CONTESTED, resolve by having all but one holder release.
Role-as-identity (recommended)
When a session exists to serve one role, use the role name AS its agent identity (FULCRA_COORD_AGENT=coord-maintainer) — see fulcra-agent-presence's "Pick your identity by ROLE" section. Claim the role's lease while you act as it. Know what each guard does and does not catch:
- Different ids claiming an exclusive role (e.g.
coord-maintainerand a stray
claude-code:host:repo): two FRESH lease shards (within sla_hours) → roles status reports CONTESTED. A stale stray shard yields HELD, not CONTESTED. Detected.
- Two sessions under the SAME id string: they write the SAME lease shard (shard names derive from
the id), so leases alone CANNOT see this — last write silently wins. Since the session-nonce verify was shipped, the engine detects this automatically: every roles claim writes a session nonce into the lease and compares on refresh — a foreign nonce prints a loud stderr WARNING ("nonce mismatch ... same-id double-acting"), and claiming with no local state over an existing shard prints a takeover note. Heed those. The manual fallback, in this order at the start of every work burst: (1) roles status --json — proceed only if VACANT or the sole holder is your id; (2) read your lease shard raw (fulcra-api file download team//roles//leases/.md — learn your ` by listing the leases dir, or from presence beat output, which prints the same key) and compare its timestamp` to when YOU last claimed — a fresher timestamp you did not write means another session is acting under your id; (3) only then re-claim to refresh. Re-claiming FIRST destroys that evidence.
Multi-host variants (coord-maintainer@host1, @host2) are acceptable when one role legitimately runs in several places — each host claims the SAME role (roles claim coord-maintainer --agent coord-maintainer@host1), never a role named after the variant. Such a role needs policy: shared: on exclusive it would sit in permanent CONTESTED by construction — and note shared trades away the CONTESTED collision guard for that role. Keep the role doc's maintainer: field a distinct SUPERVISING identity (e.g. maintainer: ash): vacancy escalations are assigned to that field, so pointing it at the role itself mails the alert to the very inbox that just went dark.
Escalate a vacancy — engine decides, you act
The engine already computed escalation_due above. When it is true, perform the single-file actions (these are reliable as prose):
- Write today's dedupe marker
roles//escalations/.md(first-writer-wins). - Drop a message into the maintainer's inbox
(team//member//inbox/__role-vacant-.md) per the fulcra-agent-teams inbox lifecycle, stating which role is vacant and for how long.
Park a role (dormancy)
To deliberately leave a role unattended without alarming — a reviewer on leave, a seasonal on-call — set dormant_until: in the role doc's frontmatter (e.g. dormant_until: 2026-08-05T09:00:00Z). While that timestamp is in the future the ENGINE treats the role as DORMANT: roles status prints DORMANT (until ) instead of VACANT and the mechanical escalate sweep suppresses its vacancy escalation on every heartbeat host — no agent-side convention required. Escalation resumes automatically once the date passes (past-or-absent dormant_until = normal behavior); a live lease outranks the park (a held-and-dormant role still shows HELD). An unparseable dormant_until fails OPEN — it is treated as absent, a stderr note is printed, and escalation still fires — so a typo can never silently mute a role. Unpark early by deleting the field.
When to use
- Establishing "someone owns X" in a team without pinning it to one session.
- Routing work by role ("the reviewer") instead of by name.
- Making sure a critical function (on-call, maintainer) is never silently unattended.
Efficiency (per the teams OKF directive)
If you keep a roles/index.md (optional — see "Establish a role"), do not index every lease or escalation marker — describe the leases/ and escalations/ directories as a whole. Keep the team log.md for role creation and handoff milestones, not every lease refresh.
See [references/roles-cli.md](references/roles-cli.md) for exact commands.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ashfulcra
- Source: ashfulcra/fulcra-tools
- License: MIT
- Homepage: https://fulcradynamics.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.