Files
AOS/agency-agents/skills/license-lifecycle/SKILL.md
T
Z User 136379c666 feat: zeroclaw agentic agency architecture — agents, skills, Rust crates
- 18 agent specs across Software, Support, Marketing, Cross-cutting
  (orchestrator + 7 software + 5 support + 3 cross-cutting + leads-finder)
- 8 reusable skills (handoff, pr-review, dokploy-deploy, campaign-structure,
  content-calendar, ticket-triage, license-lifecycle, invoice-draft)
- 3 JSON schemas: handoff, deliverable, approval
- Policies: autonomy levels, tool risk classification, compliance (DSGVO/GoBD/UWG)
- routing.toml: model tiers T1/T2/T3 + provider config (PII gating)
- Rust workspace (5 crates, all compile + 16 tests pass):
  - aos-mcp: tool registry + risk tagging
  - aos-policy: autonomy levels, budget enforcement, approval requests
  - aos-license: ed25519 license issue/verify (real crypto + CLI binary)
  - aos-ledger: integer-cents money math, gapless numbering, VAT, audit chain
  - aos-sync: frontmatter validator (18/18 specs pass), CLI binary
- CLAUDE.md entry point with architecture overview + roadmap
2026-10-30 13:01:03 +00:00

94 lines
4.8 KiB
Markdown

---
name: license-lifecycle
version: 1.0.0
applies_to: [license-lead, license-ops-agent]
risk: high
---
# License Lifecycle
## When to use
When a task requires issuing, renewing, extending, or revoking a software
license key for a client. Issuing is high-risk because keys are
cryptographically signed and bound to client identity; revoking is always
human-approved.
## Steps
1. Read the task: client record, product/SKU, license type
(subscription / perpetual / trial), binding (domain / instance id /
seat count), and requested expiry.
2. Confirm the client's entitlement in AOS: signed contract / order covering
this SKU and quantity. No entitlement → `blocked`.
3. **Issue via the `aos-license` Rust crate only.** The crate generates an
Ed25519-signed key bound to the requested domain/instance and records
(key id, client id, product, binding, issued_at, expires_at, signing
key id). **Never invent or format a key string in the prompt** — any key
produced outside the crate is invalid and a security incident.
4. Bind the key to the domain / instance / seat count as recorded by the
crate. Rebinding requires a revoke + reissue, not an in-place edit.
5. Set expiry per the contract. For subscriptions, schedule renewal
reminders (30 / 7 / 1 days before expiry) via AOS scheduled tasks. For
trials, set the trial expiry and a single reminder.
6. Write the license record to AOS via the crate's `commit` call (the crate
owns the write). Record the **key id** (not the key itself) in the AOS
note — the key is delivered through a documented secure channel, never
pasted in a ticket or commit.
7. Deliver the key to the client via a handoff to `accounting-lead` or
`support-lead` (a welcome email → `send_client_communication` approval).
The agent never calls a send tool; first client delivery is always
human-approved.
8. For renewal / extension: re-run step 3 with the existing license id,
updated expiry, and a fresh signature. Old expiry is retained in the
audit log (GoBD — no deletion of prior state).
9. For revocation: do **not** revoke directly. Compose an `ApprovalRequest`
(`schemas/approval.json`): `action: revoke_license`, `risk: high`,
`rationale` (cancellation / abuse / chargeback / security incident),
`diff_summary` (license id, client id, product, binding, reason),
`payload: { license_id, client_id, reason, effective_at }`.
10. On approval, the policy crate calls `aos:revoke_license`. The crate marks
the license `revoked` with timestamp + reason and retains the record
(GoBD — revoked licenses are retained, never deleted).
11. Write a note on the task: action taken, license id, binding, expiry,
approver (for revocation), AOS record ref.
## Inputs
- A task with `task_id`, client id, product/SKU, license type, binding,
and expiry.
- The client's entitlement record in AOS (contract / order).
- For revocation: a documented reason (cancellation / abuse / chargeback /
security incident).
## Outputs
An `AgentDeliverable` (`schemas/deliverable.json`) with:
- `status`: `done` (issued / renewed) | `needs_approval` (revoke pending) |
`blocked` (no entitlement / missing binding / invalid request)
- `deliverables[]`: the AOS license record ref (`aos_record`), the key id
(not the key), the scheduled reminder task refs.
- `risks[]`: trial-to-paid assumptions, binding ambiguity, expiry-vs-contract
mismatch, entitlement inferred.
- `cost`: tokens only (no external spend; the crate does the signing).
## Guard rails / compliance
- **Keys are generated only by the `aos-license` Rust crate.** Any key
string produced by an LLM in the prompt is invalid and treated as a
security incident — do not paste, format, or "example" a key.
- **Revocation is always human-approved** via an `ApprovalRequest` of
action `revoke_license`. No auto-revoke, no auto-expire-shortening.
- **GoBD**: revoked and expired licenses are **retained**, never deleted;
history (issuance, renewal, revocation) is append-only in the audit log.
- **DSGVO**: license keys are credentials. Do not paste them into tickets,
commits, chat, or LLM prompts. Deliver only through documented secure
channels; first client delivery is human-approved.
- **Binding integrity**: changing the binding (domain/instance/seat) is a
revoke + reissue, never an in-place edit. Expiry must match the contract
— shorter is a client-rights violation → `blocked`.
- Reissuing a lost key requires verifying the requester is the contract
holder — never reissue on an unverified support request.
## References
- `schemas/approval.json` — `revoke_license` action
- `schemas/deliverable.json` — return envelope
- `policies/compliance.md` — GoBD retention, DSGVO, secrets
- `policies/tool-risk.md` — `aos:revoke_license` is `risk: high`
- `crates/aos-license` — Ed25519 signing, gapless license id, audit log