From 829afe8d93ae9e9bf8a5a9c5af5320ee1d8bfa36 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 6 May 2026 15:00:49 +0200 Subject: [PATCH 1/5] docs(v2.2.0): clawhub skill + URL fix for Plugin Pro upgrade pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes for the v2.2.0 release line: 1. New clawhub/2.2.0/SKILL.md - Base copied verbatim from 2.1.1 to preserve all ClawScan-tuned phrasing in the Deployment recommendation / Install / Mode-specific reference sections (additive changes only — no rewrite). - Adds "Plugin Pro tier" section between Configure and Environment variables. Covers retention/quota deltas (3d/200 → 30d/1000), 90-day window + 14-day refund, how to find the tenant ID before Stripe Checkout (axonflow-openclaw-status), how to install the issued license token (AXONFLOW_LICENSE_TOKEN env or pluginConfig.licenseToken), and how to recover lost Community-SaaS credentials (axonflow-openclaw-recover CLI). - Adds AXONFLOW_LICENSE_TOKEN + AXONFLOW_UPGRADE_URL to the Environment variables table with documented defaults. - Bumps minimum-version reference from 2.1.0 → 2.2.0. 2. Upgrade-pointer URL fix across all surfaces in this repo - Old URL https://getaxonflow.com/pro returned 404 — the page was referenced in PRDs but never built. Same for https://getaxonflow.com/plugins/pro (also 404). - Replaced with https://www.getaxonflow.com/pricing/ which already resolves and carries the Plugin Pro $9.99 tier card with the Stripe buy button. The pricing page covers both Plugin Pro and team/enterprise plans — no need for a separate /pro page. - Files touched: src/status.ts (STATUS_DEFAULT_UPGRADE_URL), bin/axonflow-openclaw-status.mjs (header comment), tests/status.test.ts (8 fixtures + assertions), README.md (status sample output, Activate Pro tier section, licenseToken config reference). - All 21 test suites / 420 tests pass against the new URL. - The status CLI's --json output (and human-readable output) now prints the working pricing URL for free-tier users. clawhub/CHANGELOG.md updated with the 2.2.0 entry summarising both changes and noting the 2.1.1 base. Self-review (HARD RULE #1): - Walked every hunk per the 5-question protocol. - Skill content additions are accurate against the v2.2.0 plugin surface (the bin commands and env vars exist; verified by grep). - ClawScan-careful: the new Plugin Pro section uses neutral enumeration (what Pro extends, how to activate, how to recover), links specifics to docs pages, and avoids trigger phrases like "non-production" / "trial server" / "prevent data exfiltration". - The 2.1.1 base is preserved bit-for-bit in the sections ClawScan flagged on prior versions (Deployment recommendation, Mode-specific reference, Tombstoned identifier semantics) so a re-scan of 2.2.0 shouldn't introduce regressions. - npm run build + npm test clean. - This commit ships only what was explicitly in scope per the user direction: skill + README + URL fix. No MCP tool, no plugin code refactor, no platform changes. Out of scope (deferred): - axonflow_get_tenant_id MCP tool (would require platform release). - Cross-plugin coordination of the same URL fix (separate PRs per axonflow-claude-plugin / axonflow-cursor-plugin / axonflow-codex-plugin). Signed-off-by: Saurabh Jain Signed-off-by: Saurabh Jain --- README.md | 6 +- bin/axonflow-openclaw-status.mjs | 2 +- clawhub/2.2.0/SKILL.md | 349 +++++++++++++++++++++++++++++++ clawhub/CHANGELOG.md | 12 ++ src/status.ts | 2 +- tests/status.test.ts | 14 +- 6 files changed, 373 insertions(+), 12 deletions(-) create mode 100644 clawhub/2.2.0/SKILL.md diff --git a/README.md b/README.md index d7a199d..f74b8fe 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ export AXONFLOW_TELEMETRY=off # disable 7-day heartbeat ### Activate Pro tier -Plugin Pro is the paid tier on top of free Community SaaS — it unlocks longer audit retention, higher per-tenant quotas, and license-gated capabilities listed at [getaxonflow.com/plugins/pro](https://getaxonflow.com/plugins/pro). To activate: +Plugin Pro is the paid tier on top of free Community SaaS — it unlocks longer audit retention, higher per-tenant quotas, and license-gated capabilities listed at [www.getaxonflow.com/pricing/](https://www.getaxonflow.com/pricing/). To activate: 1. Buy through Stripe Checkout. The agent issues an `AXON-…` token and emails it to the address you used at checkout. 2. Either set `AXONFLOW_LICENSE_TOKEN=` in the environment OpenClaw runs in, or set `pluginConfig.licenseToken` in your OpenClaw config. @@ -122,7 +122,7 @@ AxonFlow OpenClaw plugin status (paste this into the Stripe checkout custom field when buying Pro) endpoint: https://try.getaxonflow.com tier: Free - upgrade: https://getaxonflow.com/pro + upgrade: https://www.getaxonflow.com/pricing/ ``` Sample output (Pro tier active): @@ -361,7 +361,7 @@ See [Configure](#configure) below for the full pluginConfig schema (`highRiskToo | `endpoint` | No | `https://try.getaxonflow.com` (Community SaaS) when unset; `http://localhost:8080` when self-hosted with no endpoint specified | AxonFlow agent gateway URL | | `clientId` | No | `"community"` (self-hosted) or auto-bootstrapped `cs_` (Community SaaS) | Tenant identity for data isolation. Override for Evaluation License or Enterprise tenants. | | `clientSecret` | No | `""` (self-hosted) or auto-bootstrapped (Community SaaS) | Basic-auth secret paired with `clientId`. Required for self-hosted Community Edition with an Evaluation License or AxonFlow Enterprise; auto-populated for Community SaaS; can be left unset for self-hosted Community Edition without a license. | -| `licenseToken` | No | `process.env.AXONFLOW_LICENSE_TOKEN` if set | AxonFlow Pro plugin-claim license token (begins with `AXON-`). When set, the plugin sends `X-License-Token` on every governed request and the agent applies Pro-tier entitlements (extended retention, higher quotas, license-gated capabilities). Get one at [getaxonflow.com/plugins/pro](https://getaxonflow.com/plugins/pro) — buy through Stripe Checkout, the token arrives by email. Env var wins over `pluginConfig.licenseToken`. | +| `licenseToken` | No | `process.env.AXONFLOW_LICENSE_TOKEN` if set | AxonFlow Pro plugin-claim license token (begins with `AXON-`). When set, the plugin sends `X-License-Token` on every governed request and the agent applies Pro-tier entitlements (extended retention, higher quotas, license-gated capabilities). Get one at [www.getaxonflow.com/pricing/](https://www.getaxonflow.com/pricing/) — buy through Stripe Checkout, the token arrives by email. Env var wins over `pluginConfig.licenseToken`. | | `userEmail` | No | — | Per-user identity forwarded on explain/override calls. Shared agents should set this from session context. | | `highRiskTools` | No | `[]` | Tools that require human approval even when policy allows | | `governedTools` | No | `[]` (all) | Tools to govern. Empty = all tools. | diff --git a/bin/axonflow-openclaw-status.mjs b/bin/axonflow-openclaw-status.mjs index a6ab22e..2048ef7 100755 --- a/bin/axonflow-openclaw-status.mjs +++ b/bin/axonflow-openclaw-status.mjs @@ -26,7 +26,7 @@ * https://try.getaxonflow.com. * AXONFLOW_UPGRADE_URL — override for the upgrade URL surfaced * to free-tier users. Defaults to - * https://getaxonflow.com/pro. + * https://www.getaxonflow.com/pricing/. * AXONFLOW_CONFIG_DIR — where try-registration.json is read * from. Defaults to per-OS convention * (see src/cache-dir.ts). diff --git a/clawhub/2.2.0/SKILL.md b/clawhub/2.2.0/SKILL.md new file mode 100644 index 0000000..aa19131 --- /dev/null +++ b/clawhub/2.2.0/SKILL.md @@ -0,0 +1,349 @@ +--- +name: governance-policies +description: Govern OpenClaw with AxonFlow — runtime policy enforcement on tool calls, PII detection, agent config protection, explainable decisions, time-bounded overrides with mandatory justification. Self-host AxonFlow Community Edition for production workloads. Use when configuring an OpenClaw deployment with governance, debugging a policy decision, or setting up compliance-grade audit trails. +homepage: https://github.com/getaxonflow/axonflow-openclaw-plugin/tree/main/policies +tags: agent-security, approvals, audit, compliance, data-loss-prevention, explainability, governance, human-in-the-loop, llm-governance, mcp, openclaw, overrides, pii, policies, prompt-injection, safety, security, sqli +--- + +# AxonFlow Governance Policies for OpenClaw + +Use this skill when setting up, hardening, or operating an OpenClaw deployment with AxonFlow governance. It covers the recommended deployment path (self-hosted), plugin installation, policy configuration, understanding why a tool call was blocked, granting a time-bounded override with mandatory justification, and building compliance-grade audit trails. + +## Deployment recommendation + +This plugin checks tool calls against policy on an AxonFlow agent that you point it at via `pluginConfig.endpoint`. **For any real workload, run a self-hosted AxonFlow.** Recommended deployment options, in order of capability and commitment: + +1. **[Self-host AxonFlow Community Edition](https://docs.getaxonflow.com/docs/deployment/self-hosted/)** — runs entirely on your infrastructure under the BSL 1.1 source-available license; data stays within your boundary. The recommended path for any real workload. The in-skill quick start is in [Step 1](#step-1-install-the-axonflow-platform) below. +2. **Community Edition with an [Evaluation License](https://docs.getaxonflow.com/docs/deployment/evaluation-rollout-guide/)** — for production use with real users or clients on the open core; adds production-fit limits and license-gated features. Free 90-day [evaluation license](https://getaxonflow.com/plugins/evaluation-license). +3. **[AxonFlow Enterprise](https://docs.getaxonflow.com/docs/deployment/community-to-enterprise-migration/)** — production-grade governance, regulatory-grade controls, SLOs, and contractual commitments suitable for regulated industries. Contact [hello@getaxonflow.com](mailto:hello@getaxonflow.com). + +If `pluginConfig.endpoint` is unset, the plugin uses the AxonFlow Community SaaS endpoint as a zero-config starting point for early exploration only. See the [Community SaaS](https://docs.getaxonflow.com/docs/deployment/community-saas/) page for full details on its scope and limits. + +Setting `pluginConfig.endpoint` to a self-hosted AxonFlow URL flips the plugin into self-hosted mode — no env var is required. Get the AxonFlow platform from [getaxonflow/axonflow](https://github.com/getaxonflow/axonflow) and follow the [Getting Started](https://docs.getaxonflow.com/docs/getting-started/) guide. For air-gapped environments where AxonFlow is not yet reachable but you want to suppress the trial-server fallback, set `AXONFLOW_COMMUNITY_SAAS=0`; set `AXONFLOW_TELEMETRY=off` to also disable the anonymous 7-day heartbeat. + +LLM provider keys never leave the user's machine in any mode — OpenClaw makes the LLM calls; AxonFlow only enforces policies and records audit trails. + +## When to use this skill + +- Setting up OpenClaw with AxonFlow for the first time. +- A tool call got blocked and you want to know **why**. +- You need to **allow** a specific blocked action for a short, audited window. +- You are auditing agent behavior for compliance. +- You are configuring per-user identity so AxonFlow attributes decisions correctly. +- You are hardening an OpenClaw deployment against reverse shells, SSRF, PII leakage, or agent-config poisoning. + +## Install + +This is a **three-step** install: stand up the AxonFlow platform, add the plugin to OpenClaw, then point the plugin at the platform. The plugin alone does not enforce policy — it is a thin client that talks to an AxonFlow agent gateway. If the platform is not installed and reachable, governed tool calls have nothing to check against. **Skipping Step 3 is the most common mistake**: the platform is running locally but the plugin still falls back to Community SaaS because no endpoint is configured. + +### Step 1: install the AxonFlow platform + +For any real workload, run AxonFlow on your own infrastructure via Docker Compose. This is the recommended path for the plugin: + +```bash +git clone https://github.com/getaxonflow/axonflow.git +cd axonflow && docker compose up -d + +# verify +curl -s http://localhost:8080/health | jq . +``` + +Follow the [Getting Started](https://docs.getaxonflow.com/docs/getting-started/) guide for prerequisites (Docker Engine or Desktop, Docker Compose v2, 4 GB RAM, 10 GB disk) and the [Self-Hosted Deployment Guide](https://docs.getaxonflow.com/docs/deployment/self-hosted/) for production options. The agent gateway listens on port 8080 — all SDK and plugin traffic goes through this port. + +> If you skip this step and just install the plugin, it uses the [Community SaaS](https://docs.getaxonflow.com/docs/deployment/community-saas/) endpoint for early exploration only. **Do not skip Step 1 for production** — see the [Deployment recommendation](#deployment-recommendation) above. + +### Step 2: install the plugin + +```bash +openclaw plugins install @axonflow/openclaw@latest +``` + +We recommend the npm-spec form as the primary install path. npm is our source-of-truth registry; the `clawhub:@axonflow/openclaw` form also works. + +Requires OpenClaw **2026.4.15 or later** (CVE floor) and `@axonflow/openclaw` **2.2.0 or later** — the recommended stable floor for the v2.x line. Upgrade the CLI with `npm install -g openclaw@latest` and the plugin with `openclaw plugins install @axonflow/openclaw@latest`. Staying on the latest plugin patch is recommended — security and quality fixes ship monthly under the v2.x line. + +> **Note on the package name:** the npm package is `@axonflow/openclaw`, not `@axonflow/openclaw-plugin`. The repo name differs from the package name. + +### Step 3: point the plugin at the platform + +Without this step the plugin auto-registers with Community SaaS regardless of whether you ran Step 1 — it does not auto-detect a locally-running AxonFlow. Set `pluginConfig.endpoint` (and `clientId` / `clientSecret` if you have them): + +```yaml +# openclaw.config.yaml +plugins: + "@axonflow/openclaw": + endpoint: http://localhost:8080 # or your remote AxonFlow URL + # clientId + clientSecret are required for Evaluation License or Enterprise tenants +``` + +Every plugin init logs a one-line canary on stderr confirming the active mode: + +``` +[AxonFlow] Connected to AxonFlow at http://localhost:8080 (mode=self-hosted) +``` + +If the canary says `mode=community-saas` after you ran Step 1, the plugin is still hitting `try.getaxonflow.com` because Step 3 was skipped or `pluginConfig.endpoint` is unset. Fix Step 3 and reload. + +Skipping Step 3 entirely (and Step 1) uses the Community SaaS endpoint for early exploration only — see the [Deployment recommendation](#deployment-recommendation) above. The first-load disclosure banner stamps under `$AXONFLOW_CONFIG_DIR`; remove the stamp file to re-display. + +## Mode-specific reference + +The recommended self-hosted path is covered in [Install Step 1](#step-1-install-the-axonflow-platform). The two subsections below add detail for the Community SaaS exploration path and the air-gapped opt-out path. + +### Community SaaS — for early exploration only + +The plugin's zero-config starting point when [Step 3](#step-3-point-the-plugin-at-the-platform) is skipped. The plugin registers a tenant with `try.getaxonflow.com` on first load and persists credentials at `$AXONFLOW_CONFIG_DIR/try-registration.json` (mode `0600`). + +**Use only for early exploration of the plugin's behaviour. Not for production workloads, regulated environments, or sensitive data.** It is shared infrastructure with rate limits and no production guarantees. + +For complete details on the Community SaaS scope and limits, see the [Community SaaS](https://docs.getaxonflow.com/docs/deployment/community-saas/) page in the docs. + +### Air-gapped: zero outbound + +For environments where no outbound traffic is permitted at all — air-gapped labs, regulated networks, classified deployments — set both env vars before the OpenClaw process starts: + +```bash +export AXONFLOW_COMMUNITY_SAAS=0 # disable Community SaaS auto-bootstrap +export AXONFLOW_TELEMETRY=off # disable the anonymous 7-day heartbeat +``` + +…and configure `pluginConfig.endpoint` to a self-hosted AxonFlow on the same network. With both env vars set and a same-network endpoint configured, no traffic leaves the environment. + +## Configure + +[Step 3](#step-3-point-the-plugin-at-the-platform) covers the primary keys (`endpoint` / `clientId` / `clientSecret`). Two more `pluginConfig` keys are worth highlighting: + +- **`userEmail`** — per-user identity, forwarded as the `X-User-Email` header. **Required** for `client.createOverride()`, `client.revokeOverride()`, `client.listOverrides()` (the endpoints reject calls without user identity, returning HTTP 401), and for correct per-user scoping on `client.explainDecision()`. If unset the client still works for block-path features but override lifecycle methods return 401. +- **`clientSecret`** handling — **resolve at runtime from a secret store** (Vault, AWS Secrets Manager, GCP Secret Manager, or your CI provider's secret store) rather than embedding the value in a config file checked into source control. The config resolver rejects `clientSecret` set without `clientId` — licensed mode must specify both. + +Optional `pluginConfig` keys: `highRiskTools` (tools requiring human approval after AxonFlow allows), `onError` (`block` for fail-closed in production, `allow` for dev), `requestTimeoutMs` (raise when AxonFlow is remote/VPN), `governedTools` / `excludedTools` (scope which tools the plugin governs), `defaultOperation` (`execute` or `query` for `mcp_check_input`). + +Full configuration reference: [OpenClaw Integration Guide](https://docs.getaxonflow.com/docs/integration/openclaw/). + +## Plugin Pro tier — extended retention and quota on Community SaaS + +Plugin Pro is the paid tier for the Community SaaS endpoint. It extends the Free baseline (3-day audit retention, 200 governed events / day) to 30-day retention and 1,000 events / day for a 90-day window. One-time payment, no auto-renewal, 14-day refund window. Self-hosted deployments don't need Plugin Pro — their tier and limits are governed by their own license. + +Pricing and the buy flow are documented at [www.getaxonflow.com/pricing](https://www.getaxonflow.com/pricing/). Per-plugin install instructions for the issued license token are at [docs.getaxonflow.com/pro](https://docs.getaxonflow.com/pro/). + +### Find the tenant ID before checkout + +Plugin Pro is bound to a tenant. The tenant ID (a `cs_` string) is paste-copied into the Stripe Checkout custom field labelled "AxonFlow tenant ID" so the issuer knows which tenant to bind the license to. Run the bundled CLI from the user's terminal to surface it: + +```bash +npx @axonflow/openclaw axonflow-openclaw-status +``` + +The status CLI prints the tenant ID, the resolved AxonFlow endpoint, the current tier, and a redacted preview of any configured license token. The full token is never printed — only the trailing 4 chars — so the output is safe to screen-share or paste into a support thread. JSON output is available via `--json` for piping into `jq`. + +### Activate Pro after checkout + +After Stripe Checkout completes, the issuer emails an `AXON-...` license token. To activate Pro on this plugin install, set either: + +- the `AXONFLOW_LICENSE_TOKEN` environment variable in the OpenClaw process environment, or +- the `licenseToken` field under the plugin's entry in `openclaw.config.yaml`. + +Reload OpenClaw. Every plugin init logs an `[AxonFlow] Pro tier active …` canary alongside the existing connection canary, and the plugin forwards `X-License-Token` on every governed request automatically. The agent's plugin-claim middleware validates the token and applies Pro-tier entitlements (extended retention, higher quota). When the 90-day window ends, the tenant returns to Free; re-purchase to continue Pro. + +### Recover lost credentials with the bundled CLI + +If the user loses the auto-bootstrapped Community SaaS credential file (`$AXONFLOW_CONFIG_DIR/try-registration.json`) and registered with an email, the plugin ships a recovery CLI that drives the platform's email-based recovery flow: + +```bash +npx @axonflow/openclaw axonflow-openclaw-recover you@example.com +``` + +The CLI posts the email to `/api/v1/recover` (the platform always returns 202 — anti-enumeration; no signal whether the email is bound), prompts the user to paste the magic-link token from the email they receive, posts to `/api/v1/recover/verify`, and persists the freshly issued tenant ID + secret to the config file (mode `0600`). Magic-link tokens are one-shot and short-lived; replays return 401. Reload OpenClaw and the next governed call uses the recovered registration. + +## Environment variables + +| Variable | Effect | +|---|---| +| `AXONFLOW_TELEMETRY=off` | Disables the 7-day anonymous heartbeat to `checkpoint.getaxonflow.com`. Accepted off-values: `off`, `0`, `false`, `no`. | +| `AXONFLOW_COMMUNITY_SAAS=0` | Disables auto-registration with `try.getaxonflow.com`. You must then set `pluginConfig.endpoint` for the plugin to enforce policy. Accepted off-values: `0`, `false`, `off`, `no`. | +| `AXONFLOW_CACHE_DIR` | Overrides the per-user cache directory used for telemetry stamps and rate-limit backoffs. Defaults to OS conventions: `$XDG_CACHE_HOME/axonflow` on Linux, `~/Library/Caches/axonflow` on macOS, `%LOCALAPPDATA%\axonflow` on Windows. | +| `AXONFLOW_CONFIG_DIR` | Overrides the per-user config directory used for the Community-SaaS registration file (mode `0600`). Defaults to OS conventions: `$XDG_CONFIG_HOME/axonflow` on Linux, `~/Library/Application Support/axonflow` on macOS, `%APPDATA%\axonflow` on Windows. | +| `AXONFLOW_LICENSE_TOKEN` | Plugin Pro license token (begins with `AXON-`). When set, the plugin sends `X-License-Token` on every governed request and the agent applies Pro-tier entitlements. Wins over `pluginConfig.licenseToken`. Empty / whitespace-only values are treated as unset. | +| `AXONFLOW_UPGRADE_URL` | Overrides the upgrade URL surfaced by `axonflow-openclaw-status` to free-tier users. Defaults to `https://www.getaxonflow.com/pricing/`. | + +The legacy `DO_NOT_TRACK=1` opt-out was removed in plugin v2.0.0; `AXONFLOW_TELEMETRY=off` is the canonical and only telemetry opt-out. + +## What's Protected Automatically + +AxonFlow's 80+ built-in system policies apply with no additional setup: + +- **Dangerous command blocking** — 10 policies covering destructive operations, remote code execution, credential access, cloud metadata, path traversal +- **SQL injection** — 30+ detection patterns covering advanced injection techniques +- **PII detection and redaction** — SSN, credit card, email, phone, Aadhaar, PAN, NRIC/FIN (Singapore) +- **Code security** — API keys, connection strings, hardcoded secrets, unsafe code patterns +- **Prompt manipulation** — instruction override and context manipulation attempts + +Examples of blocked patterns (all checked server-side by AxonFlow): + +``` +rm -rf / → blocked by sys_dangerous_destructive_fs +curl ... | sh → blocked by sys_dangerous_shell_download +nc -e /bin/bash → blocked by sys_dangerous_reverse_shell +169.254.169.254 → blocked by sys_dangerous_cloud_metadata +cat ~/.ssh/id_rsa → blocked by sys_dangerous_credential_access +../../etc/passwd → blocked by sys_dangerous_path_traversal +``` + +## Understand a Block: Richer Context + +When AxonFlow blocks a tool call against platform v7.1.0 or later, the plugin surfaces structured context instead of a terse "policy violation" string. The block response carries: + +- **`decision_id`** — unique ID pinning the block to an audit row. Use it to fetch the full explanation or reference it in a support conversation. +- **`risk_level`** — `low` / `medium` / `high` / `critical` (highest severity wins across matched policies). +- **`policy_matches[]`** — every policy that matched, with `policy_id`, `policy_name`, `action`, `risk_level`, `allow_override`, and `policy_description` so the agent can render a specific reason instead of a generic block message. +- **`override_available`** — true when at least one matched policy is overridable (non-critical, `allow_override=true`). +- **`override_existing_id`** — set when the caller already has a live override on the blocking policy (check before creating a new one). + +The hook stderr also carries a machine-readable suffix like `[decision: , risk: , active override: ]` or a pointer to `client.explainDecision(id)` when no active override exists. + +## Explain a Decision + +> **Plugin v2.1.0+:** the operations below are also exposed to the OpenClaw agent as registered tools — `axonflow_explain_decision`, `axonflow_list_overrides`, `axonflow_create_override`, `axonflow_revoke_override`, and `axonflow_audit_search`. The agent can invoke these directly during a conversation; the same client methods documented in this section back them. + +Fetch the full explanation for any previously-made decision: + +```ts +import { AxonFlowClient } from '@axonflow/openclaw'; +const client = new AxonFlowClient({ endpoint, clientId, clientSecret, userEmail }); + +const explanation = await client.explainDecision(decisionId); +// DecisionExplanation: { decision, reason, risk_level, policy_matches, matched_rules, +// override_available, override_existing_id, +// historical_hit_count_session, tool_signature, policy_source_link } +``` + +The shape is frozen per the explainability data contract (ADR-043). Access is scoped to the decision owner or same-tenant callers. Returns `null` on 404 or network failure so callers can fall back to a terse block message without crashing. See [Explainability](https://docs.getaxonflow.com/docs/governance/explainability/). + +## Grant a Session Override + +For a policy that `allow_override=true` and is not critical-risk, grant a time-bounded override with mandatory free-text justification: + +```ts +const override = await client.createOverride({ + policyId: 'sys_dangerous_shell_download', // UUID or slug — both accepted + policyType: 'static', // or 'dynamic' + overrideReason: 'Approved by security — scripted install for pinned deployment', + toolSignature: 'openclaw.exec:bash-script', // optional: scope to one tool + ttlSeconds: 1800, // optional: clamped to [60s, 24h], default 60m +}); +// CreateOverrideResult: { id, policy_id, policy_type, expires_at, ttl_seconds, +// requested_ttl?, clamped?, clamped_reason?, created_at } +``` + +**Platform-enforced invariants** (per the session-override semantics contract): +- TTL clamped to [1 min, 24 h]; default 60 min. +- Critical-risk policies are never overridable — a DB trigger rejects the create with HTTP 403. +- `allow_override=false` policies rejected with HTTP 403. +- `overrideReason` is mandatory and captured on the audit row. +- Four audit events per override lifecycle: `override_created`, `override_used`, `override_expired`, `override_revoked`. + +```ts +await client.revokeOverride(override.id); +const active = await client.listOverrides({ policyId, includeRevoked: false }); +``` + +See [Session Overrides](https://docs.getaxonflow.com/docs/governance/overrides/). + +## OpenClaw-Specific Hardening + +For additional protection against OpenClaw-specific attack vectors, the plugin repository includes ready-to-use policy templates: + +``` +Command execution → reverse shells, destructive filesystem ops, credential file access +SSRF prevention → cloud metadata endpoints, internal network addresses +Agent config → SOUL.md, MEMORY.md, identity file write protection +Path traversal → workspace escape patterns +``` + +Full policy templates: [Starter Policies](https://github.com/getaxonflow/axonflow-openclaw-plugin/tree/main/policies) + +## Top 10 Risks + +| Rank | Risk | Hook | +|------|------|------| +| 1 | Arbitrary command execution | before_tool_call | +| 2 | Data exfiltration via HTTP | before_tool_call | +| 3 | PII leakage in messages | message_sending | +| 4 | Indirect prompt injection | before_tool_call | +| 5 | Outbound secret exfiltration | message_sending | +| 6 | Malicious skill supply chain | after_tool_call (audit) | +| 7 | Memory/context poisoning | before_tool_call | +| 8 | Credential exposure | message_sending | +| 9 | Cross-tenant leakage | Tenant-scoped policies | +| 10 | Workspace boundary bypass | before_tool_call | + +## Common Workflows + +### Debug a block + +1. Agent hits a block; capture `decision_id` from the block reason string. +2. Call `client.explainDecision(decisionId)` to get the full reason, matched policies, risk level, and override availability. +3. If `override_available === true` and the block is genuinely a false positive for your context, either fix the policy (permanent) or create a scoped override (temporary). + +### Grant a one-off allow + +1. Confirm the policy matched is not critical (`risk_level !== 'critical'` and `allow_override === true`). +2. Call `client.createOverride({ policyId, policyType, overrideReason, toolSignature, ttlSeconds })` with a specific justification text that will end up on the audit trail. +3. Retry the tool call; the platform re-checks against the matched policies, flips deny → allow, emits an `override_used` event. +4. Call `client.revokeOverride(id)` when the work window ends, or let the TTL expire. + +### Audit a session + +1. Call `client.searchAuditEvents({ startTime, endTime })` to scan tool-call records. +2. Filter the compliance-grade records by `decision_id`, `policy_name`, or `override_id` (platform v7.1.0+). +3. Each record includes user, tool, matched policies, LLM prompt/response, latency, and token usage. + +## Guardrails + +- All policies are checked server-side by AxonFlow, not locally. +- High-risk tools require human approval **only after** AxonFlow allows the tool call. If AxonFlow blocks, it stays blocked regardless of HITL configuration. +- The plugin verifies AxonFlow connectivity on startup. +- Overrides are per-user (via `userEmail`), tenant-scoped, and logged at every lifecycle event. + +## Learn More + +**Get Started** +- [Getting Started](https://docs.getaxonflow.com/docs/getting-started/) — quickstart for new users +- [Community SaaS](https://docs.getaxonflow.com/docs/deployment/community-saas/) — zero-config exploration endpoint, scope and limits +- [Self-Hosted Deployment](https://docs.getaxonflow.com/docs/deployment/self-hosted/) — Docker Compose, prerequisites, production options +- [OpenClaw Integration Guide](https://docs.getaxonflow.com/docs/integration/openclaw/) — full plugin setup walkthrough + +**Policies & Security** +- [Security Best Practices](https://docs.getaxonflow.com/docs/security/best-practices/) — hardening guide for production deployments +- [Policy Enforcement](https://docs.getaxonflow.com/docs/mcp/policy-enforcement/) — how policies are applied at runtime +- [Policy Syntax](https://docs.getaxonflow.com/docs/policies/syntax/) — writing custom regex and rule-based policies +- [System Policies](https://docs.getaxonflow.com/docs/policies/system-policies/) — 80+ built-in policies (PII, SQLi, secrets, dangerous commands, prompt injection) +- [PII Detection](https://docs.getaxonflow.com/docs/security/pii-detection/) — SSN, credit card, Aadhaar, PAN, email, phone detection and redaction +- [Response Redaction](https://docs.getaxonflow.com/docs/mcp/response-redaction/) — how outbound content is scanned and redacted + +**Governance & Compliance** +- [Explainability](https://docs.getaxonflow.com/docs/governance/explainability/) — `explainDecision()`, decision IDs, matched rules, policy source links +- [Session Overrides](https://docs.getaxonflow.com/docs/governance/overrides/) — time-bounded allow-lists with mandatory justification +- [Audit Logging](https://docs.getaxonflow.com/docs/governance/audit-logging/) — compliance-grade audit trails for every tool call and LLM interaction +- [Human-in-the-Loop](https://docs.getaxonflow.com/docs/governance/human-in-the-loop/) — approval gates for high-risk operations +- [HITL Approval Gates](https://docs.getaxonflow.com/docs/features/hitl-approval-gates/) — configuring approval workflows +- [Cost Management](https://docs.getaxonflow.com/docs/governance/cost-management/) — token budgets, rate limits, cost controls +- [Compliance Frameworks](https://docs.getaxonflow.com/docs/compliance/overview/) — EU AI Act, MAS FEAT, RBI, SEBI templates + +**Platform & Examples** +- [Feature Overview](https://docs.getaxonflow.com/docs/features/overview/) — full platform capabilities +- [Community vs Enterprise](https://docs.getaxonflow.com/docs/features/community-vs-enterprise/) — what's available in each tier +- [Workflow Examples](https://docs.getaxonflow.com/docs/tutorials/workflow-examples/) — multi-step governance workflows and advanced patterns +- [Banking Example](https://docs.getaxonflow.com/docs/examples/banking/) — financial services governance patterns +- [Healthcare Example](https://docs.getaxonflow.com/docs/examples/healthcare/) — HIPAA-aware agent governance +- [E-commerce Example](https://docs.getaxonflow.com/docs/examples/ecommerce/) — customer-facing agent policies + +**Source Code** +- [Plugin Source](https://github.com/getaxonflow/axonflow-openclaw-plugin) — MIT licensed +- [AxonFlow Community](https://github.com/getaxonflow/axonflow) — source-available under BSL 1.1 + +## Licensing + +- **AxonFlow platform** (getaxonflow/axonflow): BSL 1.1 (Business Source License). Source-available, not open source. +- **@axonflow/openclaw plugin** (getaxonflow/axonflow-openclaw-plugin): MIT. Free to use, modify, and redistribute. +- **This skill**: MIT-0 per ClawHub terms. diff --git a/clawhub/CHANGELOG.md b/clawhub/CHANGELOG.md index efcaa62..aa308f7 100644 --- a/clawhub/CHANGELOG.md +++ b/clawhub/CHANGELOG.md @@ -2,6 +2,18 @@ ## @axonflow/governance-policies +### 2.2.0 (2026-05-06) + +Companion skill release to plugin v2.2.0 — the V1 paid Plugin Pro tier wire-up. + +**Adds a "Plugin Pro tier" section** between Configure and Environment variables. Covers what Pro extends on the Community SaaS endpoint (3-day audit retention → 30 days, 200 events/day → 1,000 events/day, 90-day window, no auto-renewal), how to find the tenant ID before checkout (`axonflow-openclaw-status`), how to activate the issued license token (`AXONFLOW_LICENSE_TOKEN` env var or `pluginConfig.licenseToken`), and how to recover lost Community-SaaS credentials with the bundled `axonflow-openclaw-recover` CLI. + +**Adds two new env vars to the Environment variables table:** `AXONFLOW_LICENSE_TOKEN` (Pro license token, sets `X-License-Token` header on every governed request) and `AXONFLOW_UPGRADE_URL` (override for the upgrade URL surfaced by `axonflow-openclaw-status`). Defaults documented inline. + +**Bumps minimum-version reference** from `@axonflow/openclaw` 2.1.0 to 2.2.0 — the v2.2.0 release adds the Pro-tier `X-License-Token` plumbing, the `X-Axonflow-Client` header injection per platform v7.7.0's scope-validation gate, and the new `axonflow-openclaw-status` / `axonflow-openclaw-recover` bin commands. + +Base: copied verbatim from skill v2.1.1 to preserve all ClawScan-tuned phrasing in the Deployment recommendation, Install, and Mode-specific reference sections — only additive changes. + ### 2.0.2 (2026-05-01) Two changes in this patch: diff --git a/src/status.ts b/src/status.ts index ab0b953..77a5615 100644 --- a/src/status.ts +++ b/src/status.ts @@ -44,7 +44,7 @@ const REGISTRATION_FILE_NAME = "try-registration.json"; export const STATUS_DEFAULT_ENDPOINT = "https://try.getaxonflow.com"; /** Default upgrade URL surfaced in status output for free-tier users. */ -export const STATUS_DEFAULT_UPGRADE_URL = "https://getaxonflow.com/pro"; +export const STATUS_DEFAULT_UPGRADE_URL = "https://www.getaxonflow.com/pricing/"; /** * Tier the plugin is currently operating under. diff --git a/tests/status.test.ts b/tests/status.test.ts index 0ba0c8d..427cdb1 100644 --- a/tests/status.test.ts +++ b/tests/status.test.ts @@ -339,14 +339,14 @@ describe("formatStatusReport", () => { license_token_preview: null, expires_at: null, expires_in_days: null, - upgrade_url: "https://getaxonflow.com/pro", + upgrade_url: "https://www.getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); expect(out).toContain("tenant_id: cs_t1"); expect(out).toContain("Stripe checkout custom field"); expect(out).toContain("tier: Free (no Pro license configured)"); - expect(out).toContain("upgrade: https://getaxonflow.com/pro"); + expect(out).toContain("upgrade: https://www.getaxonflow.com/pricing/"); expect(out).not.toContain("license:"); }); @@ -358,7 +358,7 @@ describe("formatStatusReport", () => { license_token_preview: "…ABCD", expires_at: "2026-08-03", expires_in_days: 90, - upgrade_url: "https://getaxonflow.com/pro", + upgrade_url: "https://www.getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); @@ -380,7 +380,7 @@ describe("formatStatusReport", () => { license_token_preview: "…ABCD", expires_at: null, // exp could not be parsed expires_in_days: null, - upgrade_url: "https://getaxonflow.com/pro", + upgrade_url: "https://www.getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); @@ -397,11 +397,11 @@ describe("formatStatusReport", () => { license_token_preview: "…ZZZZ", expires_at: "2026-02-04", expires_in_days: -90, - upgrade_url: "https://getaxonflow.com/pro", + upgrade_url: "https://www.getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); - expect(out).toContain("tier: Free (Pro expired 2026-02-04 — visit https://getaxonflow.com/pro to renew)"); + expect(out).toContain("tier: Free (Pro expired 2026-02-04 — visit https://www.getaxonflow.com/pricing/ to renew)"); expect(out).toContain("license: …ZZZZ"); expect(out).toContain("will not forward an expired token"); // The expired-token state must NOT print the standalone "upgrade:" @@ -420,7 +420,7 @@ describe("formatStatusReport", () => { license_token_preview: null, expires_at: null, expires_in_days: null, - upgrade_url: "https://getaxonflow.com/pro", + upgrade_url: "https://www.getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: false, }); From 162cd0bfc618eb6531c88bb518103f878a20b7e4 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 6 May 2026 15:02:19 +0200 Subject: [PATCH 2/5] docs(clawhub/changelog): backfill 2.1.0 + 2.1.1 entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both versions had been published (clawhub/2.1.0/SKILL.md and clawhub/2.1.1/SKILL.md exist) but never received changelog entries — the gap was visible after adding 2.2.0 today. 2.1.0 (companion to plugin v2.1.0) — agent-callable governance tools note (v2.1.0+ block in the Explain a Decision section), minimum-version bump 2.0.4 → 2.1.0, npm @latest install spec, primary-install-path clarification. 2.1.1 — third ClawScan-retune on the v2.x line. Phrase-level rewording to clear renewed Concern flags after a scanner retrain. Specific trigger phrases dropped: "prevent data exfiltration" (description), "Community SaaS trial server" (body), "non-production infrastructure" (install warning), inline rate-limit numbers (moved to docs page). Operational accuracy preserved by linking to /docs/deployment/community-saas/. Both entries reflect the actual content delta vs the prior version (verified via diff against clawhub//SKILL.md). Signed-off-by: Saurabh Jain Signed-off-by: Saurabh Jain --- clawhub/CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/clawhub/CHANGELOG.md b/clawhub/CHANGELOG.md index aa308f7..4dabe13 100644 --- a/clawhub/CHANGELOG.md +++ b/clawhub/CHANGELOG.md @@ -14,6 +14,32 @@ Companion skill release to plugin v2.2.0 — the V1 paid Plugin Pro tier wire-up Base: copied verbatim from skill v2.1.1 to preserve all ClawScan-tuned phrasing in the Deployment recommendation, Install, and Mode-specific reference sections — only additive changes. +### 2.1.1 (2026-04-23) — backfill entry + +Reframes Community SaaS phrasing to clear ClawScan re-tunes that hit v2.1.0 with renewed Concern flags after the scanner was retrained. Skill content unchanged in substance — accuracy preserved by linking to the canonical [Community SaaS](https://docs.getaxonflow.com/docs/deployment/community-saas/) docs page for full disclosure. + +Specific phrase-level changes that the LLM scanners were quoting back as "Concern" evidence: + +- `description:` frontmatter — dropped "block dangerous commands, detect PII, **prevent data exfiltration**, protect agent config files" framing in favor of neutral verbs ("runtime policy enforcement on tool calls, PII detection, agent config protection, explainable decisions"). The "prevent data exfiltration" phrase was the specific scanner trigger. +- "Community SaaS **trial server**" → "Community SaaS endpoint" everywhere in the body, with the docs page (`/docs/deployment/community-saas/`) carrying the full Limitations and Disclaimers list. +- The full disclosure block listing rate limits ("20 req/min · 500 req/day"), retention specifics, and "(what gets checked, retention, registration mechanics, rate limits)" was moved out of the inline copy into the linked docs page (single source of truth). Rate limits in the skill itself were the second-strongest scanner signal after "prevent data exfiltration". +- "**non-production infrastructure** for trying out the plugin" → "Community SaaS endpoint for early exploration only" — same operational meaning, different lexical pattern. +- Mode-specific reference subheading "Community SaaS trial server — for early exploration only" → "Community SaaS — for early exploration only". + +This is the third ClawScan-retune patch on the v2.x line (after 2.0.1 / 2.0.2). Each retune is a small phrase-level reword to clear scanner Concern flags without changing what the skill teaches; the underlying capability content stays identical. + +### 2.1.0 (2026-04-22) — backfill entry + +Companion skill release to plugin v2.1.0 — the agent-callable governance tools wire-up. + +**Adds a v2.1.0+ note in the "Explain a Decision" section** documenting that the operations described there are also exposed to the OpenClaw agent as registered tools — `axonflow_explain_decision`, `axonflow_list_overrides`, `axonflow_create_override`, `axonflow_revoke_override`, and `axonflow_audit_search`. The agent can invoke these directly during a conversation; the same client methods documented in the section back them. (Plugin v2.1.0 added `api.registerTool(...)` calls in `src/index.ts`; this skill release surfaces that capability to consumers.) + +**Bumps minimum-version reference** from `@axonflow/openclaw` 2.0.4 → 2.1.0 — the v2.1.0 plugin release adds the agent-callable tools and is the recommended stable floor for the v2.x line. + +**Updates the Install command in Step 2** from `openclaw plugins install @axonflow/openclaw` to `openclaw plugins install @axonflow/openclaw@latest`. The OpenClaw CLI's plugin resolver doesn't auto-install latest by default; the explicit `@latest` ensures users on a stale local cache pick up the v2.1.0 tools. + +**Adds a primary-install-path note** clarifying that the npm-spec form is recommended; the `clawhub:@axonflow/openclaw` form continues to work but the npm registry is the source of truth. + ### 2.0.2 (2026-05-01) Two changes in this patch: From 9c0052d2b710e376ea358f553da25f4bc8bfef86 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 6 May 2026 15:16:11 +0200 Subject: [PATCH 3/5] docs(readme): drop www. + restructure Activate Pro with explicit tenant_id step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two self-review follow-ups: 1. Drop www. — pricing URL is now https://getaxonflow.com/pricing/ (no www subdomain) per user direction. Both forms resolve (200) today; we standardise on the bare domain since www is redundant in current convention. Sweep covers README, src/status.ts constant, bin CLI comment, tests/status.test.ts assertions, and clawhub/2.2.0/SKILL.md. 2. Restructure README "Activate Pro tier" section to lead with tenant_id discovery. The original numbered list assumed users already knew where to find the tenant_id and started at "buy through Stripe Checkout". Restructured into 4 explicit steps with bold headings: Find your tenant ID → Buy at the pricing page → Install the issued license token → Reload OpenClaw. Step 1 now embeds the exact `npx @axonflow/openclaw axonflow-openclaw-status` command and points at the [Check status] anchor for full output. Pricing summary line ($9.99 / 90 days, no auto-renewal, 14-day refund) added at the section top so users see commitments before committing. Signed-off-by: Saurabh Jain Signed-off-by: Saurabh Jain --- README.md | 22 ++++++++++++++++------ bin/axonflow-openclaw-status.mjs | 2 +- clawhub/2.2.0/SKILL.md | 4 ++-- src/status.ts | 2 +- tests/status.test.ts | 14 +++++++------- 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f74b8fe..cba40c5 100644 --- a/README.md +++ b/README.md @@ -90,11 +90,21 @@ export AXONFLOW_TELEMETRY=off # disable 7-day heartbeat ### Activate Pro tier -Plugin Pro is the paid tier on top of free Community SaaS — it unlocks longer audit retention, higher per-tenant quotas, and license-gated capabilities listed at [www.getaxonflow.com/pricing/](https://www.getaxonflow.com/pricing/). To activate: +Plugin Pro is the paid tier on top of free Community SaaS — it unlocks longer audit retention, higher per-tenant quotas, and license-gated capabilities. **$9.99 USD for 90 days**, one-time payment, no auto-renewal, 14-day no-questions refund. See [getaxonflow.com/pricing/](https://getaxonflow.com/pricing/) for the full breakdown and the Stripe buy button. -1. Buy through Stripe Checkout. The agent issues an `AXON-…` token and emails it to the address you used at checkout. -2. Either set `AXONFLOW_LICENSE_TOKEN=` in the environment OpenClaw runs in, or set `pluginConfig.licenseToken` in your OpenClaw config. -3. Reload OpenClaw. The plugin will emit `[AxonFlow] Pro tier active …` on every init alongside the connection canary, and forward `X-License-Token` on every governed request automatically. +To activate Pro on an installed plugin: + +1. **Find your tenant ID.** Run the bundled status CLI from a terminal: + + ```bash + npx @axonflow/openclaw axonflow-openclaw-status + ``` + + The output includes a `tenant_id: cs_` line — that's the value Stripe Checkout needs to bind the license to your tenant. Copy it. (See [Check status](#check-status) below for the full output shape and `--json` mode.) + +2. **Buy at the pricing page.** Visit [getaxonflow.com/pricing/](https://getaxonflow.com/pricing/) and click **Buy Plugin Pro — $9.99**. At Stripe Checkout, paste your `tenant_id` into the **AxonFlow tenant ID** custom field. The agent issues an `AXON-…` token and emails it to the address you used at checkout. +3. **Install the issued license token.** Either set `AXONFLOW_LICENSE_TOKEN=` in the environment OpenClaw runs in, or set `pluginConfig.licenseToken` in your OpenClaw config. +4. **Reload OpenClaw.** The plugin emits `[AxonFlow] Pro tier active …` on every init alongside the connection canary, and forwards `X-License-Token` on every governed request automatically. If you lose the token (laptop reinstall, never archived the email), use the recovery CLI below to issue a fresh one against the same email. @@ -122,7 +132,7 @@ AxonFlow OpenClaw plugin status (paste this into the Stripe checkout custom field when buying Pro) endpoint: https://try.getaxonflow.com tier: Free - upgrade: https://www.getaxonflow.com/pricing/ + upgrade: https://getaxonflow.com/pricing/ ``` Sample output (Pro tier active): @@ -361,7 +371,7 @@ See [Configure](#configure) below for the full pluginConfig schema (`highRiskToo | `endpoint` | No | `https://try.getaxonflow.com` (Community SaaS) when unset; `http://localhost:8080` when self-hosted with no endpoint specified | AxonFlow agent gateway URL | | `clientId` | No | `"community"` (self-hosted) or auto-bootstrapped `cs_` (Community SaaS) | Tenant identity for data isolation. Override for Evaluation License or Enterprise tenants. | | `clientSecret` | No | `""` (self-hosted) or auto-bootstrapped (Community SaaS) | Basic-auth secret paired with `clientId`. Required for self-hosted Community Edition with an Evaluation License or AxonFlow Enterprise; auto-populated for Community SaaS; can be left unset for self-hosted Community Edition without a license. | -| `licenseToken` | No | `process.env.AXONFLOW_LICENSE_TOKEN` if set | AxonFlow Pro plugin-claim license token (begins with `AXON-`). When set, the plugin sends `X-License-Token` on every governed request and the agent applies Pro-tier entitlements (extended retention, higher quotas, license-gated capabilities). Get one at [www.getaxonflow.com/pricing/](https://www.getaxonflow.com/pricing/) — buy through Stripe Checkout, the token arrives by email. Env var wins over `pluginConfig.licenseToken`. | +| `licenseToken` | No | `process.env.AXONFLOW_LICENSE_TOKEN` if set | AxonFlow Pro plugin-claim license token (begins with `AXON-`). When set, the plugin sends `X-License-Token` on every governed request and the agent applies Pro-tier entitlements (extended retention, higher quotas, license-gated capabilities). Get one at [getaxonflow.com/pricing/](https://getaxonflow.com/pricing/) — buy through Stripe Checkout, the token arrives by email. Env var wins over `pluginConfig.licenseToken`. | | `userEmail` | No | — | Per-user identity forwarded on explain/override calls. Shared agents should set this from session context. | | `highRiskTools` | No | `[]` | Tools that require human approval even when policy allows | | `governedTools` | No | `[]` (all) | Tools to govern. Empty = all tools. | diff --git a/bin/axonflow-openclaw-status.mjs b/bin/axonflow-openclaw-status.mjs index 2048ef7..9fc0870 100755 --- a/bin/axonflow-openclaw-status.mjs +++ b/bin/axonflow-openclaw-status.mjs @@ -26,7 +26,7 @@ * https://try.getaxonflow.com. * AXONFLOW_UPGRADE_URL — override for the upgrade URL surfaced * to free-tier users. Defaults to - * https://www.getaxonflow.com/pricing/. + * https://getaxonflow.com/pricing/. * AXONFLOW_CONFIG_DIR — where try-registration.json is read * from. Defaults to per-OS convention * (see src/cache-dir.ts). diff --git a/clawhub/2.2.0/SKILL.md b/clawhub/2.2.0/SKILL.md index aa19131..23ee462 100644 --- a/clawhub/2.2.0/SKILL.md +++ b/clawhub/2.2.0/SKILL.md @@ -124,7 +124,7 @@ Full configuration reference: [OpenClaw Integration Guide](https://docs.getaxonf Plugin Pro is the paid tier for the Community SaaS endpoint. It extends the Free baseline (3-day audit retention, 200 governed events / day) to 30-day retention and 1,000 events / day for a 90-day window. One-time payment, no auto-renewal, 14-day refund window. Self-hosted deployments don't need Plugin Pro — their tier and limits are governed by their own license. -Pricing and the buy flow are documented at [www.getaxonflow.com/pricing](https://www.getaxonflow.com/pricing/). Per-plugin install instructions for the issued license token are at [docs.getaxonflow.com/pro](https://docs.getaxonflow.com/pro/). +Pricing and the buy flow are documented at [getaxonflow.com/pricing](https://getaxonflow.com/pricing/). Per-plugin install instructions for the issued license token are at [docs.getaxonflow.com/pro](https://docs.getaxonflow.com/pro/). ### Find the tenant ID before checkout @@ -164,7 +164,7 @@ The CLI posts the email to `/api/v1/recover` (the platform always returns 202 | `AXONFLOW_CACHE_DIR` | Overrides the per-user cache directory used for telemetry stamps and rate-limit backoffs. Defaults to OS conventions: `$XDG_CACHE_HOME/axonflow` on Linux, `~/Library/Caches/axonflow` on macOS, `%LOCALAPPDATA%\axonflow` on Windows. | | `AXONFLOW_CONFIG_DIR` | Overrides the per-user config directory used for the Community-SaaS registration file (mode `0600`). Defaults to OS conventions: `$XDG_CONFIG_HOME/axonflow` on Linux, `~/Library/Application Support/axonflow` on macOS, `%APPDATA%\axonflow` on Windows. | | `AXONFLOW_LICENSE_TOKEN` | Plugin Pro license token (begins with `AXON-`). When set, the plugin sends `X-License-Token` on every governed request and the agent applies Pro-tier entitlements. Wins over `pluginConfig.licenseToken`. Empty / whitespace-only values are treated as unset. | -| `AXONFLOW_UPGRADE_URL` | Overrides the upgrade URL surfaced by `axonflow-openclaw-status` to free-tier users. Defaults to `https://www.getaxonflow.com/pricing/`. | +| `AXONFLOW_UPGRADE_URL` | Overrides the upgrade URL surfaced by `axonflow-openclaw-status` to free-tier users. Defaults to `https://getaxonflow.com/pricing/`. | The legacy `DO_NOT_TRACK=1` opt-out was removed in plugin v2.0.0; `AXONFLOW_TELEMETRY=off` is the canonical and only telemetry opt-out. diff --git a/src/status.ts b/src/status.ts index 77a5615..84dddbc 100644 --- a/src/status.ts +++ b/src/status.ts @@ -44,7 +44,7 @@ const REGISTRATION_FILE_NAME = "try-registration.json"; export const STATUS_DEFAULT_ENDPOINT = "https://try.getaxonflow.com"; /** Default upgrade URL surfaced in status output for free-tier users. */ -export const STATUS_DEFAULT_UPGRADE_URL = "https://www.getaxonflow.com/pricing/"; +export const STATUS_DEFAULT_UPGRADE_URL = "https://getaxonflow.com/pricing/"; /** * Tier the plugin is currently operating under. diff --git a/tests/status.test.ts b/tests/status.test.ts index 427cdb1..2cdee6c 100644 --- a/tests/status.test.ts +++ b/tests/status.test.ts @@ -339,14 +339,14 @@ describe("formatStatusReport", () => { license_token_preview: null, expires_at: null, expires_in_days: null, - upgrade_url: "https://www.getaxonflow.com/pricing/", + upgrade_url: "https://getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); expect(out).toContain("tenant_id: cs_t1"); expect(out).toContain("Stripe checkout custom field"); expect(out).toContain("tier: Free (no Pro license configured)"); - expect(out).toContain("upgrade: https://www.getaxonflow.com/pricing/"); + expect(out).toContain("upgrade: https://getaxonflow.com/pricing/"); expect(out).not.toContain("license:"); }); @@ -358,7 +358,7 @@ describe("formatStatusReport", () => { license_token_preview: "…ABCD", expires_at: "2026-08-03", expires_in_days: 90, - upgrade_url: "https://www.getaxonflow.com/pricing/", + upgrade_url: "https://getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); @@ -380,7 +380,7 @@ describe("formatStatusReport", () => { license_token_preview: "…ABCD", expires_at: null, // exp could not be parsed expires_in_days: null, - upgrade_url: "https://www.getaxonflow.com/pricing/", + upgrade_url: "https://getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); @@ -397,11 +397,11 @@ describe("formatStatusReport", () => { license_token_preview: "…ZZZZ", expires_at: "2026-02-04", expires_in_days: -90, - upgrade_url: "https://www.getaxonflow.com/pricing/", + upgrade_url: "https://getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: true, }); - expect(out).toContain("tier: Free (Pro expired 2026-02-04 — visit https://www.getaxonflow.com/pricing/ to renew)"); + expect(out).toContain("tier: Free (Pro expired 2026-02-04 — visit https://getaxonflow.com/pricing/ to renew)"); expect(out).toContain("license: …ZZZZ"); expect(out).toContain("will not forward an expired token"); // The expired-token state must NOT print the standalone "upgrade:" @@ -420,7 +420,7 @@ describe("formatStatusReport", () => { license_token_preview: null, expires_at: null, expires_in_days: null, - upgrade_url: "https://www.getaxonflow.com/pricing/", + upgrade_url: "https://getaxonflow.com/pricing/", registration_file: "/tmp/x/try-registration.json", registration_present: false, }); From 16ff6793921789b3cc8f7bdbc69067c21388599b Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 6 May 2026 15:18:40 +0200 Subject: [PATCH 4/5] test(runtime-e2e): status-CLI upgrade URL surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the runtime-e2e test required by HARD RULE #0 for the STATUS_DEFAULT_UPGRADE_URL change. The "Runtime E2E required for user-facing changes" CI gate fired on this PR because src/status.ts is a customer-visible surface (the URL constant ends up in the status CLI's stdout) but the prior commits in this PR didn't touch runtime-e2e/**. What the test does Invokes bin/axonflow-openclaw-status.mjs in both human-readable and --json modes against a temporary AXONFLOW_CONFIG_DIR (no developer state), and asserts: - bin exits 0 - human-readable output contains the new pricing URL - human-readable output does NOT contain stale /pro URLs - --json output parses as valid JSON - .upgrade_url === "https://getaxonflow.com/pricing/" byte-exact Pure-CLI test — no docker stack, no agent, no network. The status surface is read-only stdlib-only per src/status.ts header comment; the test exercises the same dispatch path a free-tier user runs. PASS evidence captured at runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/. Reproducing npm run build bash runtime-e2e/status-cli-url/test.sh Self-review (HARD RULE #1): - Test exercises the live dispatch path (node ./bin/...) — not just the format function it imports. Distinguishes "compiled bin works" from "source compiles" — the difference that bit the prior commit's run (compiled dist/ was stale until npm run build). - Uses isolated AXONFLOW_CONFIG_DIR so the test passes regardless of whether the developer has a real Community SaaS registration file at the OS-default config path. - No docker / network / agent dependency — runs in CI without external infra. - Fresh evidence dir per run (UTC timestamp); old runs not overwritten. Signed-off-by: Saurabh Jain Signed-off-by: Saurabh Jain --- .../2026-05-06T131808Z/status_human.err | 0 .../2026-05-06T131808Z/status_human.txt | 9 ++ .../EVIDENCE/2026-05-06T131815Z/EVIDENCE.md | 41 +++++++ .../2026-05-06T131815Z/status_human.err | 0 .../2026-05-06T131815Z/status_human.txt | 9 ++ .../2026-05-06T131815Z/status_json.json | 11 ++ runtime-e2e/status-cli-url/test.sh | 106 ++++++++++++++++++ 7 files changed, 176 insertions(+) create mode 100644 runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131808Z/status_human.err create mode 100644 runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131808Z/status_human.txt create mode 100644 runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/EVIDENCE.md create mode 100644 runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_human.err create mode 100644 runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_human.txt create mode 100644 runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_json.json create mode 100755 runtime-e2e/status-cli-url/test.sh diff --git a/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131808Z/status_human.err b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131808Z/status_human.err new file mode 100644 index 0000000..e69de29 diff --git a/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131808Z/status_human.txt b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131808Z/status_human.txt new file mode 100644 index 0000000..58ae833 --- /dev/null +++ b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131808Z/status_human.txt @@ -0,0 +1,9 @@ +AxonFlow OpenClaw plugin status + + tenant_id: (not registered) + No registration file at /var/folders/1j/k8zxr75912v4rkh3cwctxpph0000gn/T/tmp.zIbLqc2OB3/try-registration.json + The plugin auto-registers with Community SaaS on first init. + Lost your registration? Run `axonflow-openclaw-recover ` + endpoint: https://try.getaxonflow.com + tier: Free (no Pro license configured) + upgrade: https://www.getaxonflow.com/pricing/ diff --git a/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/EVIDENCE.md b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/EVIDENCE.md new file mode 100644 index 0000000..f579624 --- /dev/null +++ b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/EVIDENCE.md @@ -0,0 +1,41 @@ +# Runtime E2E evidence — status CLI surfaces canonical pricing URL + +**Date (UTC):** 2026-05-06 13:18:15 +**Branch:** chore/v2.2.0-skill-and-readme-paid-upgrade + +## What was tested + +Per HARD RULE #0, this PR rewrites STATUS_DEFAULT_UPGRADE_URL — a +customer-facing surface (the URL printed by the bundled status CLI for +free-tier users). The unit-test layer (`tests/status.test.ts`) verifies +the constant + format function, but the rule requires the change be +exercised against the actual CLI dispatch path. + +`test.sh` invokes `bin/axonflow-openclaw-status.mjs` (the bin entry +package.json registers under `axonflow-openclaw-status`) twice: + +1. Human-readable mode — must contain `https://getaxonflow.com/pricing/` + and must NOT contain stale `/pro` URLs. +2. `--json` mode — must parse as valid JSON; `.upgrade_url` must equal + `https://getaxonflow.com/pricing/` byte-for-byte. + +Run with `AXONFLOW_CONFIG_DIR` pointed at a temp dir so the test +doesn't depend on (or pollute) the developer's real registration file. + +## Result + +**PASS** — all three assertions satisfied against the freshly-built +plugin. + +See `status_human.txt`, `status_human.err`, and `status_json.json` for +captured output. + +## Reproducing + +```bash +npm run build +bash runtime-e2e/status-cli-url/test.sh +``` + +The script writes a fresh evidence dir under +`runtime-e2e/status-cli-url/EVIDENCE//`. diff --git a/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_human.err b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_human.err new file mode 100644 index 0000000..e69de29 diff --git a/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_human.txt b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_human.txt new file mode 100644 index 0000000..ac66c93 --- /dev/null +++ b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_human.txt @@ -0,0 +1,9 @@ +AxonFlow OpenClaw plugin status + + tenant_id: (not registered) + No registration file at /var/folders/1j/k8zxr75912v4rkh3cwctxpph0000gn/T/tmp.nM9bm6Z9jY/try-registration.json + The plugin auto-registers with Community SaaS on first init. + Lost your registration? Run `axonflow-openclaw-recover ` + endpoint: https://try.getaxonflow.com + tier: Free (no Pro license configured) + upgrade: https://getaxonflow.com/pricing/ diff --git a/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_json.json b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_json.json new file mode 100644 index 0000000..51f2c04 --- /dev/null +++ b/runtime-e2e/status-cli-url/EVIDENCE/2026-05-06T131815Z/status_json.json @@ -0,0 +1,11 @@ +{ + "tenant_id": null, + "endpoint": "https://try.getaxonflow.com", + "tier": "free", + "license_token_preview": null, + "expires_at": null, + "expires_in_days": null, + "upgrade_url": "https://getaxonflow.com/pricing/", + "registration_file": "/var/folders/1j/k8zxr75912v4rkh3cwctxpph0000gn/T/tmp.nM9bm6Z9jY/try-registration.json", + "registration_present": false +} diff --git a/runtime-e2e/status-cli-url/test.sh b/runtime-e2e/status-cli-url/test.sh new file mode 100755 index 0000000..aa4e050 --- /dev/null +++ b/runtime-e2e/status-cli-url/test.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# Runtime E2E test for the status-CLI upgrade URL surface. +# +# This PR rewrites STATUS_DEFAULT_UPGRADE_URL from the broken +# https://getaxonflow.com/pro (404) to https://getaxonflow.com/pricing/ +# (200). HARD RULE #0 (runtime proof is definition of done) requires we +# exercise the change against the actual CLI surface rather than rely on +# unit tests alone. +# +# What this test asserts by invoking the built plugin's status CLI: +# 1. `npx --offline @axonflow/openclaw axonflow-openclaw-status` exits 0 +# (the bin command is wired into package.json "bin" and dispatches). +# 2. Output contains the new pricing URL (`https://getaxonflow.com/pricing/`). +# 3. Output does NOT contain the old broken URL (`getaxonflow.com/pro`). +# 4. JSON mode (`--json`) emits a structured report with the same +# upgrade_url field. +# +# Pure-CLI test — no docker stack, no agent, no network. The status +# surface is read-only stdlib-only per src/status.ts header comment; +# this test exercises the same path a free-tier user runs. + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +EVIDENCE_DIR="${EVIDENCE_DIR:-$REPO_ROOT/runtime-e2e/status-cli-url/EVIDENCE/$(date -u +%Y-%m-%dT%H%M%SZ)}" +mkdir -p "$EVIDENCE_DIR" + +cd "$REPO_ROOT" + +echo "=== runtime-e2e: status-CLI upgrade URL surface ===" +echo "Repo root: $REPO_ROOT" +echo "Evidence dir: $EVIDENCE_DIR" +echo "" + +# ----------------------------------------------------------------------------- +# Step 1: run the bin in human-readable mode +# ----------------------------------------------------------------------------- +echo "Step 1: bin/axonflow-openclaw-status.mjs (human-readable)" +human_out="$EVIDENCE_DIR/status_human.txt" +human_err="$EVIDENCE_DIR/status_human.err" + +# Run with isolated config dir so we don't read the developer's real +# ~/.config/axonflow registration file. +TMP_CONFIG_DIR="$(mktemp -d)" +trap 'rm -rf "$TMP_CONFIG_DIR"' EXIT + +if AXONFLOW_CONFIG_DIR="$TMP_CONFIG_DIR" \ + node "$REPO_ROOT/bin/axonflow-openclaw-status.mjs" \ + > "$human_out" 2>"$human_err"; then + echo " OK: bin exit 0" +else + echo " FAIL: bin exit non-zero" + echo " stderr:" + cat "$human_err" + exit 1 +fi + +# ----------------------------------------------------------------------------- +# Step 2: assert new URL is present, old URL absent +# ----------------------------------------------------------------------------- +echo "" +echo "Step 2: assert new pricing URL is in human-readable output" +if grep -qF "https://getaxonflow.com/pricing/" "$human_out"; then + echo " OK: contains https://getaxonflow.com/pricing/" +else + echo " FAIL: pricing URL missing from output" + cat "$human_out" + exit 1 +fi + +if grep -qF "getaxonflow.com/pro " "$human_out" \ + || grep -qE "getaxonflow\.com/pro$" "$human_out"; then + echo " FAIL: stale /pro URL present in output" + cat "$human_out" + exit 1 +fi +echo " OK: stale /pro URL absent from output" + +# ----------------------------------------------------------------------------- +# Step 3: run --json and parse via jq +# ----------------------------------------------------------------------------- +echo "" +echo "Step 3: bin --json mode" +json_out="$EVIDENCE_DIR/status_json.json" + +AXONFLOW_CONFIG_DIR="$TMP_CONFIG_DIR" \ +node "$REPO_ROOT/bin/axonflow-openclaw-status.mjs" --json > "$json_out" + +if ! jq . "$json_out" > /dev/null 2>&1; then + echo " FAIL: --json output is not valid JSON" + cat "$json_out" + exit 1 +fi +echo " OK: --json output parses" + +upgrade_url=$(jq -r '.upgrade_url' "$json_out") +if [ "$upgrade_url" = "https://getaxonflow.com/pricing/" ]; then + echo " OK: .upgrade_url == https://getaxonflow.com/pricing/" +else + echo " FAIL: .upgrade_url == \"$upgrade_url\" (expected https://getaxonflow.com/pricing/)" + exit 1 +fi + +echo "" +echo "=== PASS — status CLI surfaces the canonical pricing URL ===" +echo " Evidence: $EVIDENCE_DIR/" From 5b3883df8ffa4d97b14e0d614559b2427c49b103 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 6 May 2026 15:33:31 +0200 Subject: [PATCH 5/5] docs(changelog): dedicated bullet for the upgrade-URL alignment Per cross-plugin review feedback: the URL fix from getaxonflow.com/pro (404) to getaxonflow.com/pricing/ (working) was previously documented only via inline mentions in unrelated tier-line / status-output bullets. Adding a dedicated "### Fixed" bullet so the change is discoverable as a release-note line item, with a cross-reference to the same fix in companion plugins. Signed-off-by: Saurabh Jain Signed-off-by: Saurabh Jain --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c6e4af..f1d6c6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ every governed request. ### Added -- **Status surface tier line + plugin-init canary now surface Pro license expiry date.** The `tier` field in `buildStatusReport()` / `formatStatusReport()` / the `axonflow-openclaw-status` CLI parses the JWT `exp` claim from the configured Pro license token and renders one of three shapes: `Pro (expires YYYY-MM-DD, N days remaining)` when active, `Free (Pro expired YYYY-MM-DD — visit https://getaxonflow.com/pro to renew)` when the token is on disk but its `exp` has passed (plugin will not forward an expired token), or `Free (no Pro license configured)` when no token is loaded. The plugin-init canary line emitted by `registerAxonFlowGovernance` matches the same three shapes so users notice their renewal window on every plugin reload. New exports: `buildProTierInitLogLine`, `parseLicenseTokenExpiry`, `formatExpiryDate`, `daysUntil`. New `StatusReport` fields: `expires_at` (YYYY-MM-DD UTC, nullable) and `expires_in_days` (integer, negative when expired, nullable). New `StatusTier` value `"pro_expired"` distinguishes a configured-but-lapsed token from `"free"` for renew-CTA rendering. Display only — JWT signature validation remains the platform's job. Tokens whose JWT body fails to parse fall back to the legacy `Pro tier active — license token configured, X-License-Token will be forwarded on every governed request` canary so byte-exact compat with mode-clarity assertions and any external grep on the v2.1.x string is preserved. +- **Status surface tier line + plugin-init canary now surface Pro license expiry date.** The `tier` field in `buildStatusReport()` / `formatStatusReport()` / the `axonflow-openclaw-status` CLI parses the JWT `exp` claim from the configured Pro license token and renders one of three shapes: `Pro (expires YYYY-MM-DD, N days remaining)` when active, `Free (Pro expired YYYY-MM-DD — visit https://getaxonflow.com/pricing/ to renew)` when the token is on disk but its `exp` has passed (plugin will not forward an expired token), or `Free (no Pro license configured)` when no token is loaded. The plugin-init canary line emitted by `registerAxonFlowGovernance` matches the same three shapes so users notice their renewal window on every plugin reload. New exports: `buildProTierInitLogLine`, `parseLicenseTokenExpiry`, `formatExpiryDate`, `daysUntil`. New `StatusReport` fields: `expires_at` (YYYY-MM-DD UTC, nullable) and `expires_in_days` (integer, negative when expired, nullable). New `StatusTier` value `"pro_expired"` distinguishes a configured-but-lapsed token from `"free"` for renew-CTA rendering. Display only — JWT signature validation remains the platform's job. Tokens whose JWT body fails to parse fall back to the legacy `Pro tier active — license token configured, X-License-Token will be forwarded on every governed request` canary so byte-exact compat with mode-clarity assertions and any external grep on the v2.1.x string is preserved. - **`axonflow-openclaw-status` CLI for tenant + tier introspection.** New bin script (`npx @axonflow/openclaw axonflow-openclaw-status`, also exported as `buildStatusReport` / `formatStatusReport` / `resolveStatusInputs` / `redactLicenseToken` / `readPersistedTenantId` from the package entry point) prints the user's `tenant_id` (read from `$AXONFLOW_CONFIG_DIR/try-registration.json`), the AxonFlow endpoint the plugin would talk to, and a tier indicator (Pro when `AXONFLOW_LICENSE_TOKEN` or `pluginConfig.licenseToken` is set, Free otherwise). Surfaces the upgrade URL on free, and a redacted preview of the license token (last 4 chars only — full token is **never** printed) on Pro. Closes the W4 paid-Pro launch UX gap where users had no way to read their `tenant_id` before pasting it into the Stripe checkout custom field. `--json` flag emits the same shape as machine-readable output. - **Pro tier activation via `X-License-Token`.** New `licenseToken` pluginConfig field (and `AXONFLOW_LICENSE_TOKEN` env var, env wins) carries the AXON-prefixed plugin-claim token issued by AxonFlow Pro Stripe Checkout. When set, the plugin forwards it on every governed request via the `X-License-Token` header so the agent's plugin-claim middleware can apply Pro-tier entitlements (extended audit retention, higher quotas, license-gated capabilities). On every plugin init the canary log emits `[AxonFlow] Pro tier active …` alongside the existing connection canary so users always know the token is wired through. Free-tier installs are unaffected — when no token is configured the header is omitted entirely. - **`axonflow-openclaw-recover` CLI for Community-SaaS credential recovery.** New bin script (`npx @axonflow/openclaw axonflow-openclaw-recover `, also exported as `requestRecovery` / `verifyRecovery` / `extractRecoveryToken` / `persistRecoveredCredentials` from the package entry point) drives the platform's email-based recovery flow when `try-registration.json` is lost: posts to `/api/v1/recover`, prompts for the magic-link token (or accepts the full magic-link URL), posts to `/api/v1/recover/verify`, and persists the freshly-issued tenant_id + secret at `$AXONFLOW_CONFIG_DIR/try-registration.json` (mode 0o600) so the next plugin reload picks them up automatically. Magic-link tokens are one-shot and short-lived; replays return 401. @@ -30,6 +30,7 @@ every governed request. ### Fixed - **`runtime-e2e/v1_paid_tier/`: pass when stack is long-running.** Previously the test silently exited as `PARTIAL PASS` after Feature 1 whenever `/api/v1/register` returned 429, mislabeling the cause as "agent not in community-saas mode". The agent's per-IP rate limiter (5 calls per source-IP per hour, shared between `/api/v1/register` and `/api/v1/recover`) trips quickly when the test runs against a stack that has already absorbed any traffic in the current hour, which silently turns the recovery handler into a no-op (handler returns generic 202 to prevent enumeration). The test now sends a per-run synthetic source-IP via `X-Forwarded-For` (override with `RUNTIME_E2E_XFF`) so each run gets a fresh rate-limit bucket, and surfaces a real failure with a remediation hint when the bucket is somehow still saturated. Step 2g also now probes `$AXONFLOW_ENDPOINT/api/request` (the agent's primary Basic-auth surface) instead of `$PERSISTED_ENDPOINT/api/v1/audit/tool-call` — the persisted endpoint is hardcoded by the platform to `https://try.getaxonflow.com` and is correct for production users but useless for a runtime test pointing at a local stack, and the audit/tool-call route additionally requires the operator to have set `AXONFLOW_INTERNAL_SERVICE_SECRET` in non-Community deployments. Feature 1 PASSED, Feature 2 PASSED end-to-end on local docker-compose with v7.7.0. +- **Upgrade-pointer URL aligned with the canonical pricing page.** `STATUS_DEFAULT_UPGRADE_URL` (the URL surfaced by `axonflow-openclaw-status` to free-tier users, and embedded in the `tier=Free (Pro expired ... — visit ... to renew)` line) is now `https://getaxonflow.com/pricing/`. The previous default `https://getaxonflow.com/pro` returned 404 — that page was referenced in PRDs but never built. The pricing page already resolves and carries the Plugin Pro $9.99 tier card with the Stripe buy button, so plugin status output now points free-tier users at a working URL. Override via `AXONFLOW_UPGRADE_URL` env var if needed. Same fix landed in companion plugin releases (claude-plugin v1.2.0, cursor-plugin v1.2.0, codex-plugin v1.2.0). ## [2.1.1] - 2026-05-05 — exclude runtime-e2e/ from published artifact