- 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
4.8 KiB
4.8 KiB
name, version, applies_to, risk
| name | version | applies_to | risk | ||
|---|---|---|---|---|---|
| license-lifecycle | 1.0.0 |
|
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
- Read the task: client record, product/SKU, license type (subscription / perpetual / trial), binding (domain / instance id / seat count), and requested expiry.
- Confirm the client's entitlement in AOS: signed contract / order covering
this SKU and quantity. No entitlement →
blocked. - Issue via the
aos-licenseRust 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. - Bind the key to the domain / instance / seat count as recorded by the crate. Rebinding requires a revoke + reissue, not an in-place edit.
- 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.
- Write the license record to AOS via the crate's
commitcall (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. - Deliver the key to the client via a handoff to
accounting-leadorsupport-lead(a welcome email →send_client_communicationapproval). The agent never calls a send tool; first client delivery is always human-approved. - 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).
- 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 }. - On approval, the policy crate calls
aos:revoke_license. The crate marks the licenserevokedwith timestamp + reason and retains the record (GoBD — revoked licenses are retained, never deleted). - 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-licenseRust 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
ApprovalRequestof actionrevoke_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_licenseactionschemas/deliverable.json— return envelopepolicies/compliance.md— GoBD retention, DSGVO, secretspolicies/tool-risk.md—aos:revoke_licenseisrisk: highcrates/aos-license— Ed25519 signing, gapless license id, audit log