{"id":"50bcbb99-fdc8-4991-88bd-f1d9fb167cd5","entityType":"agent","slug":"clawhub-burnshall-ui-eve-esi","name":"Eve online Esi Skill","canonicalUrl":"https://www.xpersona.co/agent/clawhub-burnshall-ui-eve-esi","canonicalPath":"/agent/clawhub-burnshall-ui-eve-esi","generatedAt":"2026-10-09T16:19:20.103Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"description":"Query and manage EVE Online characters via the ESI (EVE Swagger Interface) REST API. Use when the user asks about EVE Online character data, wallet balance,...","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 964 downloads reported by the source. Last updated 4/15/2026.","installCommand":"clawhub skill install kn70krghga32ef4e3s75ew2vf980rh5b:eve-esi","sourceUrl":"https://clawhub.ai/burnshall-ui/eve-esi","homepage":"https://clawhub.ai/burnshall-ui/eve-esi","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/burnshall-ui/eve-esi","kind":"source"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Eve online Esi Skill technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"stars":null,"forks":null,"downloads":964,"packageName":null,"latestVersion":"1.0.6","tractionLabel":"964 downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-03-01T01:16:03.110Z","emptyReason":null},"lastUpdatedAt":"2026-04-15T00:45:39.800Z","lastCrawledAt":"2026-03-01T01:16:03.110Z","lastIndexedAt":null,"nextCrawlAt":"2026-03-02T01:16:03.110Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.6","createdAt":"2026-02-22T02:44:47.485Z","changelog":"eve-esi 1.0.6 - Added .gitignore for better repository hygiene. - Introduced config/esi_endpoints.json for improved endpoint organization. - add pi workflow - skill provides threat intelligence for PI operations in low/null-sec systems","fileCount":13,"zipByteSize":32811},{"version":"1.0.5","createdAt":"2026-02-19T00:41:50.973Z","changelog":"eve-esi 1.0.5 changelog - Updated documentation to use a generic placeholder for SSH tunnel instructions, changing the example user and host to \"user@your-server\" instead of a specific example. - No changes to code or environment variables; only documentation was revised for clarity and privacy.","fileCount":11,"zipByteSize":23504},{"version":"1.0.4","createdAt":"2026-02-19T00:37:07.251Z","changelog":"eve-esi 1.0.4 changelog - Environment variables for EVE credentials (EVE_CLIENT_ID, EVE_TOKEN_MAIN, EVE_REFRESH_MAIN) are now fully optional—normal operation uses ~/.openclaw/eve-tokens.json directly. - Updated SKILL.md documentation to clarify that scripts auto-manage tokens, and only require env vars if using $ENV: references in dashboard configs. - Revised authentication instructions: Client ID should be passed directly to auth_flow.py; environment variables are only necessary for specific config styles. - Adjusted required flags on EVE credentials env vars from true to false, reflecting their optional usage in most setups. - No code changes to the skill itself; documentation and environment requirements only.","fileCount":null,"zipByteSize":null},{"version":"1.0.3","createdAt":"2026-02-19T00:28:14.217Z","changelog":"eve-esi 1.0.3 - Added scripts for OAuth2 authentication flow (`auth_flow.py`) and programmatic access token retrieval (`get_token.py`) - Added `README.md` with setup instructions and authentication usage - Updated docs to clarify script locations, token storage, and usage examples - First-time setup and token refresh workflow now documented for easier onboarding","fileCount":null,"zipByteSize":null},{"version":"1.0.2","createdAt":"2026-02-11T10:01:37.302Z","changelog":"- Added Data Handling section documenting exclusive communication with official EVE Online ESI and SSO, and clarifying alert/report integration privacy. - Declared EVE_REFRESH_MAIN as the primary credential for the skill.","fileCount":null,"zipByteSize":null},{"version":"1.0.1","createdAt":"2026-02-11T09:41:09.364Z","changelog":"- Added explicit environment variable definitions for EVE SSO and notification integrations (Telegram, Discord) in SKILL.md. - Removed the sample README.md file. - No functional code or API changes in this version; documentation and configuration only.","fileCount":null,"zipByteSize":null},{"version":"1.0.0","createdAt":"2026-02-08T23:59:35.203Z","changelog":"eve-esi 1.0.0 – initial release - Provides EVE Online character management via the ESI (EVE Swagger Interface) REST API. - Supports queries for wallet, assets, skills, location, clones, implants, and more. - Includes public and authenticated endpoint documentation with example curl and Python script usage. - Features modular dashboard configuration for alerts, scheduled reports, and market tracking. - Documents best practices for authentication, pagination, caching, and API error handling.","fileCount":null,"zipByteSize":null}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install kn70krghga32ef4e3s75ew2vf980rh5b:eve-esi","setupComplexity":"low","setupSteps":["Install using `clawhub skill install kn70krghga32ef4e3s75ew2vf980rh5b:eve-esi` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/burnshall-ui/eve-esi before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T16:19:20.101Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-burnshall-ui-eve-esi/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":null},"readme":"Skill: Eve online Esi Skill\n\nOwner: burnshall-ui\n\nSummary: Query and manage EVE Online characters via the ESI (EVE Swagger Interface) REST API. Use when the user asks about EVE Online character data, wallet balance,...\n\nTags: latest:1.0.5\n\nVersion history:\n\nv1.0.6 | 2026-02-22T02:44:47.485Z | user\n\neve-esi 1.0.6\n\n- Added .gitignore for better repository hygiene.\n- Introduced config/esi_endpoints.json for improved endpoint organization.\n- add pi workflow\n-  skill provides threat intelligence for PI operations in low/null-sec systems\n\nv1.0.5 | 2026-02-19T00:41:50.973Z | user\n\neve-esi 1.0.5 changelog\n\n- Updated documentation to use a generic placeholder for SSH tunnel instructions, changing the example user and host to \"user@your-server\" instead of a specific example.\n- No changes to code or environment variables; only documentation was revised for clarity and privacy.\n\nv1.0.4 | 2026-02-19T00:37:07.251Z | user\n\neve-esi 1.0.4 changelog\n\n- Environment variables for EVE credentials (EVE_CLIENT_ID, EVE_TOKEN_MAIN, EVE_REFRESH_MAIN) are now fully optional—normal operation uses ~/.openclaw/eve-tokens.json directly.\n- Updated SKILL.md documentation to clarify that scripts auto-manage tokens, and only require env vars if using $ENV: references in dashboard configs.\n- Revised authentication instructions: Client ID should be passed directly to auth_flow.py; environment variables are only necessary for specific config styles.\n- Adjusted required flags on EVE credentials env vars from true to false, reflecting their optional usage in most setups.\n- No code changes to the skill itself; documentation and environment requirements only.\n\nv1.0.3 | 2026-02-19T00:28:14.217Z | user\n\neve-esi 1.0.3\n\n- Added scripts for OAuth2 authentication flow (`auth_flow.py`) and programmatic access token retrieval (`get_token.py`)\n- Added `README.md` with setup instructions and authentication usage\n- Updated docs to clarify script locations, token storage, and usage examples\n- First-time setup and token refresh workflow now documented for easier onboarding\n\nv1.0.2 | 2026-02-11T10:01:37.302Z | user\n\n- Added Data Handling section documenting exclusive communication with official EVE Online ESI and SSO, and clarifying alert/report integration privacy.\n- Declared EVE_REFRESH_MAIN as the primary credential for the skill.\n\nv1.0.1 | 2026-02-11T09:41:09.364Z | user\n\n- Added explicit environment variable definitions for EVE SSO and notification integrations (Telegram, Discord) in SKILL.md.\n- Removed the sample README.md file.\n- No functional code or API changes in this version; documentation and configuration only.\n\nv1.0.0 | 2026-02-08T23:59:35.203Z | user\n\neve-esi 1.0.0 – initial release\n\n- Provides EVE Online character management via the ESI (EVE Swagger Interface) REST API.\n- Supports queries for wallet, assets, skills, location, clones, implants, and more.\n- Includes public and authenticated endpoint documentation with example curl and Python script usage.\n- Features modular dashboard configuration for alerts, scheduled reports, and market tracking.\n- Documents best practices for authentication, pagination, caching, and API error handling.\n\nArchive index:\n\nArchive v1.0.6: 13 files, 32811 bytes\n\nFiles: .gitignore (258b), config/esi_endpoints.json (2181b), config/example-config.json (3738b), config/schema.json (11304b), README.md (13874b), references/authentication.md (4082b), references/endpoints.md (12013b), scripts/auth_flow.py (6321b), scripts/esi_query.py (24515b), scripts/get_token.py (3364b), scripts/validate_config.py (13527b), SKILL.md (12911b), _meta.json (126b)\n\nFile v1.0.6:SKILL.md\n\n---\r\nname: eve-esi\r\ndescription: \"Query and manage EVE Online characters via the ESI (EVE Swagger Interface) REST API. Use when the user asks about EVE Online character data, wallet balance, ISK transactions, assets, skill queue, skill points, clone locations, implants, fittings, contracts, market orders, mail, industry jobs, killmails, planetary interaction, loyalty points, or any other EVE account management task.\"\r\nenv:\r\n  - name: EVE_CLIENT_ID\r\n    description: \"EVE Developer Application Client ID (from https://developers.eveonline.com/applications). Optional: only needed if using $ENV: references in your dashboard config instead of passing --client-id to auth_flow.py directly.\"\r\n    required: false\r\n    sensitive: false\r\n  - name: EVE_TOKEN_MAIN\r\n    description: \"ESI OAuth2 access token for the main character. Optional: scripts auto-manage tokens via ~/.openclaw/eve-tokens.json (written by auth_flow.py). Only set this if using $ENV: references in your dashboard config.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: EVE_REFRESH_MAIN\r\n    description: \"ESI OAuth2 refresh token for automatic access token renewal. Optional: scripts auto-manage tokens via ~/.openclaw/eve-tokens.json. Only set this if using $ENV: references in your dashboard config.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: TELEGRAM_BOT_TOKEN\r\n    description: \"Telegram Bot API token for sending alerts and reports.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: TELEGRAM_CHAT_ID\r\n    description: \"Telegram chat ID where notifications are sent.\"\r\n    required: false\r\n    sensitive: false\r\n  - name: DISCORD_WEBHOOK_URL\r\n    description: \"Discord webhook URL for sending alerts and reports.\"\r\n    required: false\r\n    sensitive: true\r\n---\r\n\r\n# Data Handling\r\n\r\nThis skill communicates exclusively with the official EVE Online ESI API (`esi.evetech.net`) and EVE SSO (`login.eveonline.com`).\r\nNo character data is exfiltrated to third-party servers.\r\nOptional integrations (Telegram, Discord) are user-configured via environment variables and only transmit alerts defined by the user.\r\n\r\n# EVE Online ESI\r\n\r\nThe ESI (EVE Swagger Interface) is the official REST API for EVE Online third-party development.\r\n\r\n- Base URL: `https://esi.evetech.net/latest`\r\n- Spec: `https://esi.evetech.net/latest/swagger.json`\r\n- API Explorer: <https://developers.eveonline.com/api-explorer>\r\n\r\n## Skill Location\r\n\r\nAll scripts live at: `~/.openclaw/workspace/skills/eve-esi/scripts/`\r\n\r\nAlways use full paths when calling scripts:\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n```\r\n\r\n## Authentication\r\n\r\nTokens are stored in `~/.openclaw/eve-tokens.json` (created by auth_flow.py, chmod 600).\r\nAll scripts (`get_token.py`, `esi_query.py`) read from this file directly — **no env vars are required for normal operation.**\r\n\r\n**First-time setup** (once per character):\r\n```bash\r\n# 1. Set up SSH tunnel on your local PC:\r\n#    ssh -L 8080:127.0.0.1:8080 user@your-server -N\r\n# 2. Run auth flow on server (pass Client ID directly):\r\npython3 ~/.openclaw/workspace/skills/eve-esi/scripts/auth_flow.py --client-id <YOUR_CLIENT_ID> --char-name main\r\n# 3. Open the shown URL in browser, log in with EVE account\r\n```\r\n\r\n**Get a fresh access token** (tokens expire after ~20min, refresh is automatic):\r\n```bash\r\nTOKEN=$(python3 ~/.openclaw/workspace/skills/eve-esi/scripts/get_token.py --char main)\r\n```\r\n\r\n**List authenticated characters:**\r\n```bash\r\npython3 ~/.openclaw/workspace/skills/eve-esi/scripts/get_token.py --list\r\n```\r\n\r\nFor full OAuth2/PKCE details: see `references/authentication.md`.\r\n\r\n## Public endpoints (no auth)\r\n\r\n```bash\r\n# Character public info\r\ncurl -s \"https://esi.evetech.net/latest/characters/2114794365/\" | python -m json.tool\r\n\r\n# Portrait URLs\r\ncurl -s \"https://esi.evetech.net/latest/characters/2114794365/portrait/\"\r\n\r\n# Corporation history\r\ncurl -s \"https://esi.evetech.net/latest/characters/2114794365/corporationhistory/\"\r\n\r\n# Bulk affiliation lookup\r\ncurl -s -X POST \"https://esi.evetech.net/latest/characters/affiliation/\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[2114794365, 95538921]'\r\n```\r\n\r\n## Character info (authenticated)\r\n\r\n```bash\r\nTOKEN=\"<your_access_token>\"\r\nCHAR_ID=\"<your_character_id>\"\r\n\r\n# Online status (scope: esi-location.read_online.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/online/\"\r\n```\r\n\r\n## Wallet\r\n\r\n```bash\r\n# Balance (scope: esi-wallet.read_character_wallet.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/wallet/\"\r\n\r\n# Journal (paginated)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/wallet/journal/?page=1\"\r\n\r\n# Transactions\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/wallet/transactions/\"\r\n```\r\n\r\n## Assets\r\n\r\n```bash\r\n# All assets (paginated; scope: esi-assets.read_assets.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/assets/?page=1\"\r\n\r\n# Resolve item locations\r\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[1234567890, 9876543210]' \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/assets/locations/\"\r\n\r\n# Resolve item names\r\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[1234567890]' \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/assets/names/\"\r\n```\r\n\r\n## Skills\r\n\r\n```bash\r\n# All trained skills + total SP (scope: esi-skills.read_skills.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/skills/\"\r\n\r\n# Skill queue (scope: esi-skills.read_skillqueue.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/skillqueue/\"\r\n\r\n# Attributes (intelligence, memory, etc.)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/attributes/\"\r\n```\r\n\r\n## Location and ship\r\n\r\n```bash\r\n# Current location (scope: esi-location.read_location.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/location/\"\r\n\r\n# Current ship (scope: esi-location.read_ship_type.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/ship/\"\r\n```\r\n\r\n## Clones and implants\r\n\r\n```bash\r\n# Jump clones + home station (scope: esi-clones.read_clones.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/clones/\"\r\n\r\n# Active implants (scope: esi-clones.read_implants.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/implants/\"\r\n```\r\n\r\n## More endpoints\r\n\r\nFor contracts, fittings, mail, industry, killmails, market orders, mining, planetary interaction, loyalty points, notifications, blueprints, standings, and all other character endpoints, see [references/endpoints.md](references/endpoints.md).\r\n\r\n## Dashboard Config\r\n\r\nThe skill supports a modular dashboard config for alerts, reports, and market tracking. Each user defines what they need in a JSON config file.\r\n\r\n- **Schema**: [config/schema.json](config/schema.json) — full JSON Schema with all fields, types, and defaults\r\n- **Example**: [config/example-config.json](config/example-config.json) — ready-to-use template\r\n\r\n### Features\r\n\r\n| Module | Description |\r\n|--------|-------------|\r\n| **Alerts** | Real-time polling for war decs, structure attacks, skill completions, wallet changes, industry jobs, PI extractors, killmails, contracts, clone jumps, mail |\r\n| **Reports** | Cron-scheduled summaries: net worth, skill queue, industry, market orders, wallet, assets |\r\n| **Market** | Price tracking with absolute thresholds and trend detection |\r\n\r\n### Security\r\n\r\nTokens should **not** be stored in plain text. Use environment variable references:\r\n\r\n```json\r\n{\r\n  \"token\": \"$ENV:EVE_TOKEN_MAIN\",\r\n  \"refresh_token\": \"$ENV:EVE_REFRESH_MAIN\"\r\n}\r\n```\r\n\r\nThe config file should live outside the workspace (e.g. `~/.openclaw/eve-dashboard-config.json`).\r\n\r\n### Validate a config\r\n\r\n```bash\r\npython scripts/validate_config.py path/to/config.json\r\n\r\n# Show example config\r\npython scripts/validate_config.py --example\r\n\r\n# Show JSON schema\r\npython scripts/validate_config.py --schema\r\n```\r\n\r\n## Using the query script\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\nTOKEN=$(python3 $SKILL/scripts/get_token.py --char main)\r\nCHAR_ID=$(python3 $SKILL/scripts/get_token.py --char main --json | python3 -c \"import sys,json; print(json.load(sys.stdin))\" 2>/dev/null)\r\n\r\n# Simple query\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" --endpoint \"/characters/$CHAR_ID/wallet/\" --pretty\r\n\r\n# Fetch all pages of assets\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" --endpoint \"/characters/$CHAR_ID/assets/\" --pages --pretty\r\n\r\n# POST request (e.g. asset names)\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" --endpoint \"/characters/$CHAR_ID/assets/names/\" \\\r\n  --method POST --body '[1234567890]' --pretty\r\n```\r\n\r\n## Best practices\r\n\r\n- **Caching**: respect the `Expires` header; do not poll before it expires.\r\n- **Error limits**: monitor `X-ESI-Error-Limit-Remain`; back off when low.\r\n- **User-Agent**: always set a descriptive User-Agent with contact info.\r\n- **Rate limits**: some endpoints (mail, contracts) have internal rate limits returning HTTP 520.\r\n- **Pagination**: check the `X-Pages` response header; iterate with `?page=N`.\r\n- **Versioning**: use `/latest/` for current stable routes. `/dev/` may change without notice.\r\n\r\n## Threat Assessment & Route Planning\r\n\r\nThe skill provides threat intelligence for PI systems in low/null-sec space. Data sources: ESI (kills, jumps, FW, incursions) and zKillboard (PVP activity).\r\n\r\n### ESI Threat Endpoints\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n\r\n# System kills (last hour) — all or filtered\r\npython3 $SKILL/scripts/esi_query.py --action system_kills --pretty\r\npython3 $SKILL/scripts/esi_query.py --action system_kills --system-ids 30002537,30045337 --pretty\r\n\r\n# System jump traffic (last hour)\r\npython3 $SKILL/scripts/esi_query.py --action system_jumps --system-ids 30045337 --pretty\r\n\r\n# System info (name, security status)\r\npython3 $SKILL/scripts/esi_query.py --action system_info --system-id 30002537 --pretty\r\n\r\n# Route planning (flags: secure, shortest, insecure)\r\npython3 $SKILL/scripts/esi_query.py --action route_plan --origin 30000142 --destination 30002537 --route-flag secure --pretty\r\n\r\n# Character location (requires auth)\r\nTOKEN=$(python3 $SKILL/scripts/get_token.py --char main)\r\npython3 $SKILL/scripts/esi_query.py --action character_location --token \"$TOKEN\" --character-id $CHAR_ID --pretty\r\n\r\n# Faction warfare systems\r\npython3 $SKILL/scripts/esi_query.py --action fw_systems --pretty\r\n\r\n# Active incursions\r\npython3 $SKILL/scripts/esi_query.py --action incursions --pretty\r\n```\r\n\r\n### Threat Assessment Scripts (Workspace)\r\n\r\nThese scripts live in `~/.openclaw/workspace/scripts/` (not in the skill repo):\r\n\r\n```bash\r\n# Threat level for specific systems\r\npython3 ~/.openclaw/workspace/scripts/threat_query.py --action threat_assessment --system-ids 30002537,30045337\r\n\r\n# Threat for all PI systems across all characters\r\npython3 ~/.openclaw/workspace/scripts/threat_query.py --action threat_assessment_pi\r\n\r\n# Route with per-system threat annotation\r\npython3 ~/.openclaw/workspace/scripts/threat_query.py --action route_annotated --origin 30000142 --destination 30002537\r\n\r\n# Route from character's current location\r\npython3 ~/.openclaw/workspace/scripts/threat_query.py --action route_annotated --character main --destination 30045337\r\n\r\n# Full PI + Threat morning briefing\r\npython3 ~/.openclaw/workspace/scripts/threat_query.py --action pi_briefing\r\n```\r\n\r\n### Threat Levels\r\n\r\n| Level | Score | Meaning |\r\n|-------|-------|---------|\r\n| `low` | 0-15 | Normaler PI-Betrieb |\r\n| `medium` | 15-40 | Schnell rein, schnell raus |\r\n| `high` | 40-80 | Nur mit Scout/Cloak |\r\n| `critical` | 80+ | NICHT reinfliegen |\r\n\r\n### Threat Cache\r\n\r\nThreat data is cached in Redis (30min TTL for ESI, 1h for zKillboard). The cache is updated every 30 minutes via cron:\r\n\r\n```bash\r\n# Update cache manually\r\npython3 ~/.openclaw/workspace/scripts/cache_threat_data.py\r\n\r\n# Show cached threat data\r\npython3 ~/.openclaw/workspace/scripts/cache_threat_data.py --check\r\n```\r\n\r\n## Resolving type IDs\r\n\r\nESI returns numeric type IDs (e.g. for ships, items, skills). Resolve names via:\r\n\r\n```bash\r\n# Single type\r\ncurl -s \"https://esi.evetech.net/latest/universe/types/587/\"\r\n\r\n# Bulk names (up to 1000 IDs)\r\ncurl -s -X POST \"https://esi.evetech.net/latest/universe/names/\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[587, 638, 11393]'\r\n```\n\nFile v1.0.6:README.md\n\n# EVE ESI Skill for OpenClaw\r\n\r\nAn [OpenClaw](https://openclaw.ai) skill for interacting with the [EVE Online ESI API](https://developers.eveonline.com/api-explorer) (EVE Swagger Interface).\r\n\r\n## Features\r\n\r\n<<<<<<< HEAD\r\n- **PKCE Authentication** — Secure OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **Multi-Character** — Store and manage tokens for unlimited characters\r\n- **PI Monitoring** — Planetary Interaction status, extractor timers, storage fill levels\r\n- **Market Prices** — Global average prices and Jita buy/sell lookups\r\n- **ESI Queries** — Reusable Python helper with pagination, rate-limit handling, and error recovery\r\n- **Threat Assessment** — System threat scoring using ESI kills/jumps + zKillboard PVP data\r\n- **Route Planning** — Annotated routes with per-system threat levels\r\n- **Dashboard Config** — Modular alert/report/market-tracking config with JSON Schema\r\n=======\r\n- **Authentication** — PKCE OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **ESI Queries** — reusable Python helper with pagination, error limits, and caching\r\n- **PI + Market Actions** — built-in actions for PI planet status and Jita price snapshots\r\n- **Multi-character** — store and manage tokens for multiple characters\r\n- **Dashboard Config** — modular alert/report/market-tracking config schema\r\n- **Reference docs** — full scope list, endpoint index, auth flow details\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n\r\n## Structure\r\n\r\n```\r\neve-esi/\r\n├── SKILL.md                        # OpenClaw skill instructions (loaded by agent)\r\n├── README.md                       # This file\r\n├── .gitignore                      # Prevents token/secret commits\r\n├── scripts/\r\n<<<<<<< HEAD\r\n│   ├── auth_flow.py                # One-time EVE SSO OAuth2 PKCE authentication\r\n│   ├── get_token.py                # Token refresh helper (auto-rotates on every use)\r\n=======\r\n│   ├── auth_flow.py                # One-time EVE SSO OAuth2 authentication\r\n│   ├── get_token.py                # Token refresh helper (auto-rotates)\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n│   ├── esi_query.py                # ESI query helper + high-level PI/market actions\r\n│   └── validate_config.py          # Dashboard config validator\r\n├── config/\r\n│   ├── schema.json                 # JSON Schema for dashboard config\r\n│   ├── example-config.json         # Ready-to-use template\r\n<<<<<<< HEAD\r\n│   └── esi_endpoints.json          # PI and market endpoint definitions\r\n=======\r\n│   └── esi_endpoints.json          # Endpoint catalog (PI + market helpers)\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n└── references/\r\n    ├── authentication.md           # EVE SSO OAuth2 + PKCE details\r\n    └── endpoints.md                # All character endpoints + scopes\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\ncd ~/.openclaw/workspace/skills\r\ngit clone https://github.com/burnshall-ui/openclaw-eve-skill eve-esi\r\n```\r\n\r\nNo pip dependencies — uses Python 3.8+ stdlib only.\r\n\r\n## Authentication Setup\r\n\r\n### Prerequisites\r\n\r\n1. Register an app at [developers.eveonline.com](https://developers.eveonline.com/applications)\r\n2. Set callback URL to `http://127.0.0.1:8080/callback`\r\n3. Select the scopes you need (PI requires `esi-planets.manage_planets.v1`)\r\n4. Note your **Client ID**\r\n\r\n### One-time auth per character\r\n\r\n```bash\r\n# If on a remote server, set up an SSH tunnel first:\r\nssh -L 8080:127.0.0.1:8080 user@your-server -N\r\n\r\n# Run the auth flow:\r\npython3 scripts/auth_flow.py --client-id <YOUR_CLIENT_ID> --char-name main\r\n\r\n# Open the shown URL in your browser and log in with your EVE account\r\n```\r\n\r\nTokens are stored in `~/.openclaw/eve-tokens.json` (chmod 600, auto-rotated).\r\n\r\n### Multiple characters\r\n\r\n```bash\r\npython3 scripts/auth_flow.py --client-id <CLIENT_ID> --char-name alt1\r\npython3 scripts/auth_flow.py --client-id <CLIENT_ID> --char-name alt2\r\n\r\n# List all authenticated characters:\r\npython3 scripts/get_token.py --list\r\n```\r\n\r\n## Quick Start\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n\r\n# Get a fresh access token (auto-refreshes on every call)\r\nTOKEN=$(python3 $SKILL/scripts/get_token.py --char main)\r\n\r\n# Wallet balance\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" \\\r\n  --endpoint \"/characters/<CHAR_ID>/wallet/\" --pretty\r\n\r\n# Skill queue\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" \\\r\n  --endpoint \"/characters/<CHAR_ID>/skillqueue/\" --pretty\r\n\r\n# All assets (paginated)\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" \\\r\n  --endpoint \"/characters/<CHAR_ID>/assets/\" --pages --pretty\r\n\r\n# PI: list all planets for a character\r\npython3 $SKILL/scripts/esi_query.py --action pi_planets \\\r\n  --token \"$TOKEN\" --character-id <CHAR_ID> --pretty\r\n\r\n# PI: parsed \"needs attention\" status per planet\r\npython3 $SKILL/scripts/esi_query.py --action pi_status \\\r\n  --token \"$TOKEN\" --character-id <CHAR_ID> --pretty\r\n\r\n# Market (public): Jita buy/sell snapshot for one type\r\npython3 $SKILL/scripts/esi_query.py --action jita_price \\\r\n  --type-id 2393 --pretty\r\n\r\n# Market (public): adjusted/average prices for all types\r\npython3 $SKILL/scripts/esi_query.py --action market_price_bulk --pretty\r\n```\r\n\r\n<<<<<<< HEAD\r\n## Planetary Interaction (PI)\r\n\r\nThe skill includes high-level PI actions that parse raw ESI data into actionable status reports.\r\n\r\n### PI Actions\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\nTOKEN=$(python3 $SKILL/scripts/get_token.py --char main)\r\nCHAR_ID=<your_character_id>\r\n\r\n# List all PI planets for a character\r\npython3 $SKILL/scripts/esi_query.py --action pi_planets \\\r\n  --token \"$TOKEN\" --character-id $CHAR_ID --pretty\r\n\r\n# Full PI status with extractor timers, storage fill, attention flags\r\npython3 $SKILL/scripts/esi_query.py --action pi_status \\\r\n  --token \"$TOKEN\" --character-id $CHAR_ID --pretty\r\n\r\n# Detailed info for a specific planet\r\npython3 $SKILL/scripts/esi_query.py --action pi_planet_detail \\\r\n  --token \"$TOKEN\" --character-id $CHAR_ID --planet-id <PLANET_ID> --pretty\r\n```\r\n\r\n### PI Status Output\r\n\r\nThe `pi_status` action returns parsed data per planet:\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `planet_name` | Resolved planet name (e.g. \"Ikoskio VII\") |\r\n| `extractors` | List with product, expiry time, hours remaining, status |\r\n| `storage_fill_pct` | Estimated launchpad/storage fill percentage |\r\n| `factories` | Input/output product routing |\r\n| `needs_attention` | `true` if extractor < 6h or storage > 80% |\r\n| `action_required` | Human-readable description of what needs to be done |\r\n\r\n### What PI can and cannot do\r\n\r\nESI provides **read-only** access to PI. The skill can:\r\n- Monitor extractor timers and warn before expiry\r\n- Track launchpad/storage fill levels\r\n- Show factory routing and production chains\r\n- Compare market prices for PI products\r\n\r\nIt **cannot** restart extractors, reroute products, or modify planet setups — that must be done in-game.\r\n\r\n## Market Prices\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n\r\n# Global average/adjusted prices for all items\r\npython3 $SKILL/scripts/esi_query.py --action market_price_bulk --pretty\r\n\r\n# Current Jita buy/sell for a specific item (e.g. Coolant = type_id 9832)\r\npython3 $SKILL/scripts/esi_query.py --action jita_price --type-id 9832 --pretty\r\n```\r\n\r\nThe `jita_price` action returns lowest sell, highest buy, spread, and order counts for The Forge region.\r\n=======\r\n### Action mode parameters\r\n\r\n- `--action` supports: `pi_planets`, `pi_planet_detail`, `pi_status`, `market_price_bulk`, `jita_price`\r\n- `--character-id` is required for PI actions\r\n- `--planet-id` is required for `pi_planet_detail`\r\n- `--type-id` is required for `jita_price`\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n\r\n## Dashboard Config\r\n\r\nSet up automated alerts, scheduled reports, and market price tracking:\r\n\r\n```bash\r\n# Copy example config\r\ncp config/example-config.json ~/.openclaw/eve-dashboard-config.json\r\n\r\n# Edit with your preferences\r\n# Use $ENV:VARIABLE_NAME for tokens — never store secrets in plain text\r\n\r\n# Validate\r\npython3 scripts/validate_config.py ~/.openclaw/eve-dashboard-config.json\r\n```\r\n\r\nSee [config/schema.json](config/schema.json) for the full schema.\r\n\r\nEndpoint presets for PI and market requests are documented in [config/esi_endpoints.json](config/esi_endpoints.json).\r\n\r\n### Alert Types\r\n\r\n| Alert | Description |\r\n|-------|-------------|\r\n| `war_declared` | New war declaration against your corp |\r\n| `structure_under_attack` | Structure attacked |\r\n| `skill_complete` | Skill training finished |\r\n| `wallet_large_deposit` | ISK deposit above threshold |\r\n| `industry_job_complete` | Manufacturing/research job done |\r\n| `pi_extractor_expired` | Planetary extraction head expired |\r\n| `killmail` | New killmail received |\r\n| `contract_expired` | Contract expired |\r\n\r\n### Report Templates\r\n\r\n| Report | Description |\r\n|--------|-------------|\r\n| `net_worth` | Total ISK across wallet + assets |\r\n| `skill_queue` | Current training status |\r\n| `industry_jobs` | Active manufacturing/research jobs |\r\n| `market_orders` | Open buy/sell orders |\r\n| `wallet_summary` | Recent transaction summary |\r\n| `assets_summary` | Top asset locations by value |\r\n\r\n## Threat Assessment & Route Planning\r\n\r\nThe skill provides threat intelligence for PI operations in low/null-sec systems.\r\n\r\n### Data Sources\r\n\r\n| Source | Data | Auth |\r\n|--------|------|------|\r\n| ESI `/universe/system_kills/` | Ship/Pod/NPC kills (last hour) | No |\r\n| ESI `/universe/system_jumps/` | Jump traffic (last hour) | No |\r\n| ESI `/route/{origin}/{destination}/` | Route planning | No |\r\n| ESI `/fw/systems/` | Faction Warfare contested systems | No |\r\n| ESI `/incursions/` | Active NPC incursions | No |\r\n| zKillboard API | PVP kills with value (last 24h) | No |\r\n\r\n### Threat Levels\r\n\r\n| Level | Score | Advice |\r\n|-------|-------|--------|\r\n| `low` | 0-15 | Normal PI operations |\r\n| `medium` | 15-40 | Quick in, quick out |\r\n| `high` | 40-80 | Scout/Cloak only |\r\n| `critical` | 80+ | Do NOT enter |\r\n\r\n### ESI Actions\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n\r\n# System kills (last hour, optionally filtered)\r\npython3 $SKILL/scripts/esi_query.py --action system_kills --system-ids 30002537 --pretty\r\n\r\n# System jump traffic\r\npython3 $SKILL/scripts/esi_query.py --action system_jumps --system-ids 30002537 --pretty\r\n\r\n# System info (name, security status)\r\npython3 $SKILL/scripts/esi_query.py --action system_info --system-id 30002537 --pretty\r\n\r\n# Route planning\r\npython3 $SKILL/scripts/esi_query.py --action route_plan --origin 30000142 --destination 30002537 --route-flag secure --pretty\r\n\r\n# Character location\r\nTOKEN=$(python3 $SKILL/scripts/get_token.py --char main)\r\npython3 $SKILL/scripts/esi_query.py --action character_location --token \"$TOKEN\" --character-id $CHAR_ID --pretty\r\n\r\n# FW systems & incursions\r\npython3 $SKILL/scripts/esi_query.py --action fw_systems --pretty\r\npython3 $SKILL/scripts/esi_query.py --action incursions --pretty\r\n```\r\n\r\n### Threat Assessment (Workspace Scripts)\r\n\r\nThe threat scoring logic and caching live in the agent workspace (`~/.openclaw/workspace/scripts/`), not in this repo. See `SKILL.md` for usage details.\r\n\r\n## Security\r\n\r\n- Tokens stored in `~/.openclaw/eve-tokens.json` with `chmod 600`\r\n- Refresh tokens rotate on every use (EVE SSO best practice)\r\n- PKCE flow — no client secret needed\r\n- Dashboard config supports `$ENV:VARIABLE_NAME` to keep secrets out of files\r\n- `.gitignore` prevents accidental token commits\r\n- **Never commit** `eve-tokens.json` or configs with real tokens\r\n\r\n## Scopes\r\n\r\nThe default auth flow requests these scopes:\r\n\r\n| Scope | Purpose |\r\n|-------|---------|\r\n| `esi-wallet.read_character_wallet.v1` | ISK balance, journal, transactions |\r\n| `esi-assets.read_assets.v1` | Item inventory |\r\n| `esi-skills.read_skills.v1` | Trained skills, SP |\r\n| `esi-skills.read_skillqueue.v1` | Skill queue |\r\n| `esi-clones.read_clones.v1` | Jump clones, home station |\r\n| `esi-clones.read_implants.v1` | Active implants |\r\n| `esi-location.read_location.v1` | Current system/station |\r\n| `esi-location.read_ship_type.v1` | Current ship |\r\n| `esi-location.read_online.v1` | Online status |\r\n| `esi-planets.manage_planets.v1` | PI colonies and extractors |\r\n| `esi-industry.read_character_jobs.v1` | Industry jobs |\r\n| `esi-markets.read_character_orders.v1` | Market orders |\r\n| `esi-contracts.read_character_contracts.v1` | Contracts |\r\n| `esi-killmails.read_killmails.v1` | Killmails |\r\n| `esi-characters.read_notifications.v1` | Notifications |\r\n| `esi-characters.read_fatigue.v1` | Jump fatigue |\r\n| `esi-mail.read_mail.v1` | EVE mail |\r\n\r\nEdit `SCOPES` in `auth_flow.py` to customize.\r\n\r\n## Requirements\r\n\r\n- Python 3.8+ (stdlib only for core ESI queries)\r\n- OpenClaw gateway (for agent integration)\r\n- **Redis** (optional, for PI market price caching)\r\n- **Python `redis` package** (optional, only needed for price cache)\r\n\r\n### Redis Setup (optional)\r\n\r\nRedis is used to cache PI market prices with a 1-hour TTL. Without it, market prices are fetched live from ESI on every request.\r\n\r\n```bash\r\n# Install Redis\r\nsudo apt install redis-server\r\nsudo systemctl enable redis-server\r\n\r\n# Install Python redis package\r\npip3 install redis\r\n\r\n# Test\r\nredis-cli ping   # → PONG\r\n```\r\n\r\nThe companion script `cache_market_prices.py` (not part of this repo, lives in the agent workspace) fetches PI product prices from ESI and caches them in Redis under the key schema `eve:market:price:{type_id}`.\r\n\r\n## Links\r\n\r\n- [EVE ESI API Explorer](https://developers.eveonline.com/api-explorer)\r\n- [EVE Developer Portal](https://developers.eveonline.com/applications)\r\n- [OpenClaw Docs](https://docs.openclaw.ai)\n\nFile v1.0.6:_meta.json\n\n{\n  \"ownerId\": \"kn70krghga32ef4e3s75ew2vf980rh5b\",\n  \"slug\": \"eve-esi\",\n  \"version\": \"1.0.6\",\n  \"publishedAt\": 1771728287485\n}\n\nFile v1.0.6:references/authentication.md\n\n# EVE SSO OAuth2 Authentication\r\n\r\nEVE ESI uses OAuth 2.0 Authorization Code flow via EVE SSO (Single Sign-On).\r\n\r\nBase SSO URL: `https://login.eveonline.com`\r\n\r\n## Prerequisites\r\n\r\n1. Register an application at <https://developers.eveonline.com/applications>\r\n2. Note your **Client ID** and **Secret Key**\r\n3. Set a **Callback URL** (e.g. `http://localhost:8080/callback`)\r\n4. Select required **Scopes** for the endpoints you need\r\n\r\n## Authorization Code Flow\r\n\r\n### Step 1: Redirect user to SSO\r\n\r\n```\r\nhttps://login.eveonline.com/v2/oauth/authorize/?response_type=code&redirect_uri=<CALLBACK_URL>&client_id=<CLIENT_ID>&scope=<SCOPES>&state=<RANDOM_STATE>\r\n```\r\n\r\n- `scope`: space-separated list (e.g. `esi-wallet.read_character_wallet.v1 esi-assets.read_assets.v1`)\r\n- `state`: random string to prevent CSRF\r\n\r\n### Step 2: Exchange authorization code for tokens\r\n\r\n```bash\r\ncurl -X POST https://login.eveonline.com/v2/oauth/token \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"grant_type=authorization_code\" \\\r\n  -d \"code=<AUTH_CODE>\" \\\r\n  -d \"client_id=<CLIENT_ID>\" \\\r\n  -d \"code_verifier=<CODE_VERIFIER>\"\r\n```\r\n\r\nResponse:\r\n\r\n```json\r\n{\r\n  \"access_token\": \"eyJ...\",\r\n  \"expires_in\": 1199,\r\n  \"token_type\": \"Bearer\",\r\n  \"refresh_token\": \"abc123...\"\r\n}\r\n```\r\n\r\n### Step 3: Refresh expired tokens\r\n\r\nAccess tokens expire after ~20 minutes. Refresh with:\r\n\r\n```bash\r\ncurl -X POST https://login.eveonline.com/v2/oauth/token \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"grant_type=refresh_token\" \\\r\n  -d \"refresh_token=<REFRESH_TOKEN>\" \\\r\n  -d \"client_id=<CLIENT_ID>\"\r\n```\r\n\r\n### Step 4: Verify token and get character ID\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer <ACCESS_TOKEN>\" \\\r\n  https://login.eveonline.com/oauth/verify\r\n```\r\n\r\nResponse includes `CharacterID`, `CharacterName`, `Scopes`.\r\n\r\n## Using tokens with ESI\r\n\r\nPass the access token as a Bearer header:\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer <ACCESS_TOKEN>\" \\\r\n  \"https://esi.evetech.net/latest/characters/<CHARACTER_ID>/wallet/\"\r\n```\r\n\r\n## PKCE (Proof Key for Code Exchange)\r\n\r\nEVE SSO supports PKCE for public clients (no secret key). Generate a `code_verifier` (random 43-128 char string) and derive `code_challenge` via SHA-256:\r\n\r\n```python\r\nimport hashlib, base64, secrets\r\ncode_verifier = secrets.token_urlsafe(64)\r\ncode_challenge = base64.urlsafe_b64encode(\r\n    hashlib.sha256(code_verifier.encode()).digest()\r\n).rstrip(b\"=\").decode()\r\n```\r\n\r\nAdd `&code_challenge=<CHALLENGE>&code_challenge_method=S256` to the authorize URL. Include `code_verifier` in the token exchange.\r\n\r\n## Required Scopes by Category\r\n\r\n| Category | Scope |\r\n|----------|-------|\r\n| Wallet | `esi-wallet.read_character_wallet.v1` |\r\n| Assets | `esi-assets.read_assets.v1` |\r\n| Skills | `esi-skills.read_skills.v1`, `esi-skills.read_skillqueue.v1` |\r\n| Clones | `esi-clones.read_clones.v1`, `esi-clones.read_implants.v1` |\r\n| Location | `esi-location.read_location.v1`, `esi-location.read_ship_type.v1`, `esi-location.read_online.v1` |\r\n| Contacts | `esi-characters.read_contacts.v1` |\r\n| Contracts | `esi-contracts.read_character_contracts.v1` |\r\n| Fittings | `esi-fittings.read_fittings.v1` |\r\n| Mail | `esi-mail.read_mail.v1` |\r\n| Calendar | `esi-calendar.read_calendar_events.v1` |\r\n| Industry | `esi-industry.read_character_jobs.v1` |\r\n| Market Orders | `esi-markets.read_character_orders.v1` |\r\n| Killmails | `esi-killmails.read_killmails.v1` |\r\n| Blueprints | `esi-characters.read_blueprints.v1` |\r\n| Notifications | `esi-characters.read_notifications.v1` |\r\n| Bookmarks | `esi-bookmarks.read_character_bookmarks.v1` |\r\n| Loyalty | `esi-characters.read_loyalty.v1` |\r\n| Mining | `esi-industry.read_character_mining.v1` |\r\n| Roles | `esi-characters.read_corporation_roles.v1` |\r\n| Standings | `esi-characters.read_standings.v1` |\r\n| Fatigue | `esi-characters.read_fatigue.v1` |\r\n| Medals | `esi-characters.read_medals.v1` |\r\n| Titles | `esi-characters.read_titles.v1` |\r\n| Agent Research | `esi-characters.read_agents_research.v1` |\r\n| FW Stats | `esi-characters.read_fw_stats.v1` |\n\nFile v1.0.6:references/endpoints.md\n\n# EVE ESI Character Endpoints Reference\r\n\r\nBase URL: `https://esi.evetech.net/latest`\r\n\r\nAll authenticated endpoints require `Authorization: Bearer <TOKEN>` header. Replace `{character_id}` with the numeric character ID from SSO verify.\r\n\r\n## Table of Contents\r\n\r\n- [Character Info](#character-info)\r\n- [Wallet](#wallet)\r\n- [Assets](#assets)\r\n- [Skills](#skills)\r\n- [Clones and Implants](#clones-and-implants)\r\n- [Location](#location)\r\n- [Contacts](#contacts)\r\n- [Contracts](#contracts)\r\n- [Calendar](#calendar)\r\n- [Fittings](#fittings)\r\n- [Industry](#industry)\r\n- [Killmails](#killmails)\r\n- [Mail](#mail)\r\n- [Market Orders](#market-orders)\r\n- [Mining](#mining)\r\n- [Notifications](#notifications)\r\n- [Loyalty Points](#loyalty-points)\r\n- [Planets (PI)](#planets-pi)\r\n- [Blueprints](#blueprints)\r\n- [Roles and Titles](#roles-and-titles)\r\n- [Standings](#standings)\r\n- [Bookmarks](#bookmarks)\r\n- [Medals](#medals)\r\n- [Agent Research](#agent-research)\r\n- [Fatigue](#fatigue)\r\n- [Faction Warfare](#faction-warfare)\r\n- [Corporation History](#corporation-history)\r\n- [Portrait](#portrait)\r\n- [Search](#search)\r\n- [Fleet](#fleet)\r\n\r\n---\r\n\r\n## Character Info\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/` | -- | Public character info (name, corp, birthday, etc.) |\r\n| GET | `/characters/{character_id}/online/` | `esi-location.read_online.v1` | Online status, last login/logout |\r\n| POST | `/characters/affiliation/` | -- | Bulk lookup corp/alliance/faction for character IDs |\r\n\r\n## Wallet\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/wallet/` | `esi-wallet.read_character_wallet.v1` | ISK balance |\r\n| GET | `/characters/{character_id}/wallet/journal/` | `esi-wallet.read_character_wallet.v1` | Wallet journal (paginated) |\r\n| GET | `/characters/{character_id}/wallet/transactions/` | `esi-wallet.read_character_wallet.v1` | Wallet transactions |\r\n\r\n## Assets\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/assets/` | `esi-assets.read_assets.v1` | All assets (paginated) |\r\n| POST | `/characters/{character_id}/assets/locations/` | `esi-assets.read_assets.v1` | Locations for specific item IDs |\r\n| POST | `/characters/{character_id}/assets/names/` | `esi-assets.read_assets.v1` | Names for specific item IDs |\r\n\r\n## Skills\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/skills/` | `esi-skills.read_skills.v1` | All trained skills + total SP |\r\n| GET | `/characters/{character_id}/skillqueue/` | `esi-skills.read_skillqueue.v1` | Current skill queue |\r\n| GET | `/characters/{character_id}/attributes/` | `esi-skills.read_skills.v1` | Character attributes (int, mem, etc.) |\r\n\r\n## Clones and Implants\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/clones/` | `esi-clones.read_clones.v1` | Jump clones and home location |\r\n| GET | `/characters/{character_id}/implants/` | `esi-clones.read_implants.v1` | Active implant type IDs |\r\n\r\n## Location\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/location/` | `esi-location.read_location.v1` | Current solar system, station/structure |\r\n| GET | `/characters/{character_id}/ship/` | `esi-location.read_ship_type.v1` | Current ship type and name |\r\n\r\n## Contacts\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/contacts/` | `esi-characters.read_contacts.v1` | Contact list |\r\n| POST | `/characters/{character_id}/contacts/` | `esi-characters.write_contacts.v1` | Add contacts |\r\n| PUT | `/characters/{character_id}/contacts/` | `esi-characters.write_contacts.v1` | Edit contacts |\r\n| DELETE | `/characters/{character_id}/contacts/` | `esi-characters.write_contacts.v1` | Delete contacts |\r\n| GET | `/characters/{character_id}/contacts/labels/` | `esi-characters.read_contacts.v1` | Contact labels |\r\n\r\n## Contracts\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/contracts/` | `esi-contracts.read_character_contracts.v1` | All contracts (paginated) |\r\n| GET | `/characters/{character_id}/contracts/{contract_id}/bids/` | `esi-contracts.read_character_contracts.v1` | Bids on a contract |\r\n| GET | `/characters/{character_id}/contracts/{contract_id}/items/` | `esi-contracts.read_character_contracts.v1` | Items in a contract |\r\n\r\n## Calendar\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/calendar/` | `esi-calendar.read_calendar_events.v1` | Upcoming events (50 max) |\r\n| GET | `/characters/{character_id}/calendar/{event_id}/` | `esi-calendar.read_calendar_events.v1` | Event details |\r\n| GET | `/characters/{character_id}/calendar/{event_id}/attendees/` | `esi-calendar.read_calendar_events.v1` | Event attendees |\r\n| PUT | `/characters/{character_id}/calendar/{event_id}/` | `esi-calendar.respond_calendar_events.v1` | Respond to event |\r\n\r\n## Fittings\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fittings/` | `esi-fittings.read_fittings.v1` | Saved fittings |\r\n| POST | `/characters/{character_id}/fittings/` | `esi-fittings.write_fittings.v1` | Create a fitting |\r\n| DELETE | `/characters/{character_id}/fittings/{fitting_id}/` | `esi-fittings.write_fittings.v1` | Delete a fitting |\r\n\r\n## Industry\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/industry/jobs/` | `esi-industry.read_character_jobs.v1` | Industry jobs (manufacturing, research, etc.) |\r\n\r\n## Killmails\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/killmails/recent/` | `esi-killmails.read_killmails.v1` | Recent killmail IDs + hashes |\r\n| GET | `/killmails/{killmail_id}/{killmail_hash}/` | -- | Full killmail details (public) |\r\n\r\n## Mail\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/mail/` | `esi-mail.read_mail.v1` | Mail headers (paginated) |\r\n| GET | `/characters/{character_id}/mail/{mail_id}/` | `esi-mail.read_mail.v1` | Single mail body |\r\n| POST | `/characters/{character_id}/mail/` | `esi-mail.send_mail.v1` | Send a mail |\r\n| PUT | `/characters/{character_id}/mail/{mail_id}/` | `esi-mail.organize_mail.v1` | Update labels / mark read |\r\n| DELETE | `/characters/{character_id}/mail/{mail_id}/` | `esi-mail.organize_mail.v1` | Delete a mail |\r\n| GET | `/characters/{character_id}/mail/labels/` | `esi-mail.read_mail.v1` | Mail labels + unread counts |\r\n| POST | `/characters/{character_id}/mail/labels/` | `esi-mail.organize_mail.v1` | Create mail label |\r\n| GET | `/characters/{character_id}/mail/lists/` | `esi-mail.read_mail.v1` | Mailing lists |\r\n\r\n## Market Orders\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/orders/` | `esi-markets.read_character_orders.v1` | Active market orders |\r\n| GET | `/characters/{character_id}/orders/history/` | `esi-markets.read_character_orders.v1` | Expired/cancelled orders (paginated) |\r\n\r\n## Mining\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/mining/` | `esi-industry.read_character_mining.v1` | Mining ledger (last 30 days) |\r\n\r\n## Notifications\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/notifications/` | `esi-characters.read_notifications.v1` | All notifications |\r\n| GET | `/characters/{character_id}/notifications/contacts/` | `esi-characters.read_notifications.v1` | Contact notifications |\r\n\r\n## Loyalty Points\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/loyalty/points/` | `esi-characters.read_loyalty.v1` | LP balances per corp |\r\n\r\n## Planets (PI)\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/planets/` | `esi-planets.manage_planets.v1` | List of colonies |\r\n| GET | `/characters/{character_id}/planets/{planet_id}/` | `esi-planets.manage_planets.v1` | Colony layout and extractors |\r\n\r\n## Blueprints\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/blueprints/` | `esi-characters.read_blueprints.v1` | All blueprints (paginated) |\r\n\r\n## Roles and Titles\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/roles/` | `esi-characters.read_corporation_roles.v1` | Corporation roles |\r\n| GET | `/characters/{character_id}/titles/` | `esi-characters.read_titles.v1` | Corporation titles |\r\n\r\n## Standings\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/standings/` | `esi-characters.read_standings.v1` | NPC standings |\r\n\r\n## Bookmarks\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/bookmarks/` | `esi-bookmarks.read_character_bookmarks.v1` | All bookmarks (paginated) |\r\n| GET | `/characters/{character_id}/bookmarks/folders/` | `esi-bookmarks.read_character_bookmarks.v1` | Bookmark folders |\r\n\r\n## Medals\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/medals/` | `esi-characters.read_medals.v1` | Awarded medals |\r\n\r\n## Agent Research\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/agents_research/` | `esi-characters.read_agents_research.v1` | Research agents and points |\r\n\r\n## Fatigue\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fatigue/` | `esi-characters.read_fatigue.v1` | Jump fatigue expiry timestamps |\r\n\r\n## Faction Warfare\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fw/stats/` | `esi-characters.read_fw_stats.v1` | FW kill/VP stats |\r\n\r\n## Corporation History\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/corporationhistory/` | -- | Public employment history |\r\n\r\n## Portrait\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/portrait/` | -- | Portrait URLs (64/128/256/512px) |\r\n\r\n## Search\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/search/` | `esi-search.search_structures.v1` | Authenticated search (includes structures) |\r\n\r\n## Fleet\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fleet/` | `esi-fleets.read_fleet.v1` | Current fleet info |\r\n\r\n---\r\n\r\n## Pagination\r\n\r\nPaginated endpoints return `X-Pages` header. Append `?page=N` (1-based). Always check `X-Pages` to determine total pages.\r\n\r\n## Caching\r\n\r\nEvery response includes `Expires` and `Last-Modified` headers. Do not request again before `Expires`. Use `If-None-Match` with the `ETag` header for conditional requests (returns 304 if unchanged).\r\n\r\n## Error Handling\r\n\r\n- `403`: Missing scope or wrong character\r\n- `404`: Resource not found\r\n- `420`: Error rate limited (back off and retry)\r\n- `502/503/504`: Upstream server issue (retry with backoff)\r\n- Check `X-ESI-Error-Limit-Remain` and `X-ESI-Error-Limit-Reset` headers\n\nFile v1.0.6:config/esi_endpoints.json\n\n{\r\n  \"pi_planets\": {\r\n    \"path\": \"/characters/{character_id}/planets/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": true,\r\n    \"scope\": \"esi-planets.manage_planets.v1\",\r\n    \"description\": \"Liste aller PI-Planeten eines Characters\"\r\n  },\r\n  \"pi_planet_detail\": {\r\n    \"path\": \"/characters/{character_id}/planets/{planet_id}/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": true,\r\n    \"scope\": \"esi-planets.manage_planets.v1\",\r\n    \"description\": \"Extraktoren, Factories, Links und Routes eines Planeten\"\r\n  },\r\n  \"universe_planet\": {\r\n    \"path\": \"/universe/planets/{planet_id}/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"description\": \"Planet-Metadaten (Name, Typ, System)\"\r\n  },\r\n  \"market_prices\": {\r\n    \"path\": \"/markets/prices/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"description\": \"Alle adjusted/average Preise (global)\"\r\n  },\r\n  \"market_orders\": {\r\n    \"path\": \"/markets/10000002/orders/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"params\": [\r\n      \"type_id\",\r\n      \"order_type\"\r\n    ],\r\n    \"description\": \"Jita Buy/Sell Orders fuer ein bestimmtes Item\"\r\n  },\r\n  \"system_kills\": {\r\n    \"path\": \"/universe/system_kills/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"description\": \"Ship/Pod/NPC Kills pro System (letzte Stunde)\"\r\n  },\r\n  \"system_jumps\": {\r\n    \"path\": \"/universe/system_jumps/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"description\": \"Jump-Traffic pro System (letzte Stunde)\"\r\n  },\r\n  \"route\": {\r\n    \"path\": \"/route/{origin}/{destination}/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"params\": [\"flag\"],\r\n    \"description\": \"Routenplanung (flags: shortest, secure, insecure)\"\r\n  },\r\n  \"system_info\": {\r\n    \"path\": \"/universe/systems/{system_id}/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"description\": \"System-Name, Security-Status, Constellation, Star\"\r\n  },\r\n  \"incursions\": {\r\n    \"path\": \"/incursions/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"description\": \"Aktive NPC-Incursions (Constellation, Staging System, State)\"\r\n  },\r\n  \"fw_systems\": {\r\n    \"path\": \"/fw/systems/\",\r\n    \"method\": \"GET\",\r\n    \"auth\": false,\r\n    \"description\": \"Faction-Warfare umkaempfte Systeme mit Ownership/Contested-Level\"\r\n  }\r\n}\n\nFile v1.0.6:config/example-config.json\n\n{\r\n  \"schema_version\": \"1.0\",\r\n\r\n  \"notification_channels\": {\r\n    \"telegram\": {\r\n      \"bot_token\": \"$ENV:TELEGRAM_BOT_TOKEN\",\r\n      \"chat_id\": \"$ENV:TELEGRAM_CHAT_ID\"\r\n    }\r\n  },\r\n\r\n  \"characters\": [\r\n    {\r\n      \"id\": 2114794365,\r\n      \"name\": \"Main Character\",\r\n      \"token\": \"$ENV:EVE_TOKEN_MAIN\",\r\n      \"refresh_token\": \"$ENV:EVE_REFRESH_MAIN\",\r\n      \"client_id\": \"$ENV:EVE_CLIENT_ID\",\r\n      \"scopes\": [\r\n        \"esi-wallet.read_character_wallet.v1\",\r\n        \"esi-skills.read_skills.v1\",\r\n        \"esi-skills.read_skillqueue.v1\",\r\n        \"esi-assets.read_assets.v1\",\r\n        \"esi-clones.read_clones.v1\",\r\n        \"esi-clones.read_implants.v1\",\r\n        \"esi-location.read_location.v1\",\r\n        \"esi-location.read_ship_type.v1\",\r\n        \"esi-location.read_online.v1\",\r\n        \"esi-characters.read_notifications.v1\",\r\n        \"esi-industry.read_character_jobs.v1\",\r\n        \"esi-markets.read_character_orders.v1\",\r\n        \"esi-contracts.read_character_contracts.v1\",\r\n        \"esi-killmails.read_killmails.v1\",\r\n        \"esi-planets.manage_planets.v1\",\r\n        \"esi-characters.read_fatigue.v1\",\r\n        \"esi-mail.read_mail.v1\"\r\n      ],\r\n      \"corporation\": {\r\n        \"id\": 98000001,\r\n        \"name\": \"My Corp\"\r\n      },\r\n      \"enabled\": true\r\n    }\r\n  ],\r\n\r\n  \"alerts\": {\r\n    \"enabled\": true,\r\n    \"check_interval\": \"5m\",\r\n    \"channels\": [\"telegram\"],\r\n    \"rules\": [\r\n      {\r\n        \"type\": \"war_declared\",\r\n        \"severity\": \"critical\"\r\n      },\r\n      {\r\n        \"type\": \"structure_under_attack\",\r\n        \"severity\": \"critical\"\r\n      },\r\n      {\r\n        \"type\": \"structure_fuel_low\",\r\n        \"severity\": \"warning\",\r\n        \"threshold\": 24\r\n      },\r\n      {\r\n        \"type\": \"skill_complete\",\r\n        \"severity\": \"info\",\r\n        \"cooldown\": \"1h\"\r\n      },\r\n      {\r\n        \"type\": \"wallet_large_deposit\",\r\n        \"severity\": \"info\",\r\n        \"threshold\": 1000000000\r\n      },\r\n      {\r\n        \"type\": \"industry_job_complete\",\r\n        \"severity\": \"info\",\r\n        \"cooldown\": \"30m\"\r\n      },\r\n      {\r\n        \"type\": \"pi_extractor_expired\",\r\n        \"severity\": \"warning\"\r\n      },\r\n      {\r\n        \"type\": \"killmail\",\r\n        \"severity\": \"info\"\r\n      },\r\n      {\r\n        \"type\": \"contract_expired\",\r\n        \"severity\": \"warning\",\r\n        \"cooldown\": \"2h\"\r\n      }\r\n    ]\r\n  },\r\n\r\n  \"reports\": {\r\n    \"enabled\": true,\r\n    \"schedule\": \"0 9,21 * * *\",\r\n    \"timezone\": \"Europe/Berlin\",\r\n    \"channels\": [\"telegram\"],\r\n    \"templates\": [\r\n      {\r\n        \"name\": \"net_worth\",\r\n        \"format\": \"short\"\r\n      },\r\n      {\r\n        \"name\": \"skill_queue\",\r\n        \"format\": \"detailed\"\r\n      },\r\n      {\r\n        \"name\": \"wallet_summary\",\r\n        \"format\": \"short\"\r\n      },\r\n      {\r\n        \"name\": \"assets_summary\",\r\n        \"format\": \"short\"\r\n      }\r\n    ]\r\n  },\r\n\r\n  \"market\": {\r\n    \"enabled\": true,\r\n    \"check_interval\": \"30m\",\r\n    \"channels\": [\"telegram\"],\r\n    \"items\": [\r\n      {\r\n        \"type_id\": 44992,\r\n        \"name\": \"PLEX\",\r\n        \"region_id\": 10000002,\r\n        \"region_name\": \"The Forge\",\r\n        \"alert_above\": 4500000,\r\n        \"alert_below\": 3500000,\r\n        \"trend_alert\": {\r\n          \"change_percent\": 10,\r\n          \"time_window\": \"1h\"\r\n        },\r\n        \"cooldown\": \"1h\"\r\n      },\r\n      {\r\n        \"type_id\": 34,\r\n        \"name\": \"Tritanium\",\r\n        \"region_id\": 10000002,\r\n        \"region_name\": \"The Forge\",\r\n        \"trend_alert\": {\r\n          \"change_percent\": 15,\r\n          \"time_window\": \"6h\"\r\n        }\r\n      },\r\n      {\r\n        \"type_id\": 16274,\r\n        \"name\": \"Skill Injector\",\r\n        \"region_id\": 10000002,\r\n        \"region_name\": \"The Forge\",\r\n        \"alert_below\": 800000000,\r\n        \"cooldown\": \"2h\"\r\n      }\r\n    ]\r\n  }\r\n}\n\nFile v1.0.6:config/schema.json\n\n{\r\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\r\n  \"title\": \"EVE Dashboard Config\",\r\n  \"description\": \"Modular config schema for the EVE Command Center. Each user configures which alerts, reports, and market trackers they need.\",\r\n  \"type\": \"object\",\r\n  \"properties\": {\r\n\r\n    \"schema_version\": {\r\n      \"type\": \"string\",\r\n      \"description\": \"Schema version for future migrations\",\r\n      \"default\": \"1.0\",\r\n      \"enum\": [\"1.0\"]\r\n    },\r\n\r\n    \"notification_channels\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Connection details for notification channels. Values can be literal or $ENV:VARIABLE_NAME references.\",\r\n      \"properties\": {\r\n        \"telegram\": {\r\n          \"type\": \"object\",\r\n          \"properties\": {\r\n            \"bot_token\": {\r\n              \"type\": \"string\",\r\n              \"description\": \"Telegram Bot Token (e.g. '123456:ABC-DEF...' or '$ENV:TELEGRAM_BOT_TOKEN')\"\r\n            },\r\n            \"chat_id\": {\r\n              \"type\": \"string\",\r\n              \"description\": \"Telegram Chat ID (e.g. '-100123456789' or '$ENV:TELEGRAM_CHAT_ID')\"\r\n            }\r\n          },\r\n          \"required\": [\"bot_token\", \"chat_id\"]\r\n        },\r\n        \"discord\": {\r\n          \"type\": \"object\",\r\n          \"properties\": {\r\n            \"webhook_url\": {\r\n              \"type\": \"string\",\r\n              \"description\": \"Discord Webhook URL (or '$ENV:DISCORD_WEBHOOK_URL')\"\r\n            }\r\n          },\r\n          \"required\": [\"webhook_url\"]\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    },\r\n\r\n    \"characters\": {\r\n      \"type\": \"array\",\r\n      \"description\": \"EVE characters to monitor, with auth tokens and granted scopes\",\r\n      \"items\": {\r\n        \"type\": \"object\",\r\n        \"properties\": {\r\n          \"id\": {\r\n            \"type\": \"integer\",\r\n            \"description\": \"EVE Character ID (from SSO /oauth/verify)\"\r\n          },\r\n          \"name\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"Display name (optional, for readability)\"\r\n          },\r\n          \"token\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"ESI Access Token (or '$ENV:EVE_TOKEN_MAIN'). Expires after ~20min.\"\r\n          },\r\n          \"refresh_token\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"ESI Refresh Token for automatic renewal (or '$ENV:EVE_REFRESH_MAIN')\"\r\n          },\r\n          \"client_id\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"EVE Developer App Client ID (or '$ENV:EVE_CLIENT_ID')\"\r\n          },\r\n          \"scopes\": {\r\n            \"type\": \"array\",\r\n            \"description\": \"List of granted ESI scopes. Validated against required scopes during config check.\",\r\n            \"items\": {\r\n              \"type\": \"string\"\r\n            },\r\n            \"examples\": [\r\n              [\"esi-wallet.read_character_wallet.v1\", \"esi-skills.read_skills.v1\", \"esi-skills.read_skillqueue.v1\"]\r\n            ]\r\n          },\r\n          \"corporation\": {\r\n            \"type\": \"object\",\r\n            \"description\": \"Corporation association (optional, otherwise derived from ESI)\",\r\n            \"properties\": {\r\n              \"id\": { \"type\": \"integer\" },\r\n              \"name\": { \"type\": \"string\" }\r\n            }\r\n          },\r\n          \"enabled\": {\r\n            \"type\": \"boolean\",\r\n            \"description\": \"Whether to actively monitor this character\",\r\n            \"default\": true\r\n          }\r\n        },\r\n        \"required\": [\"id\", \"token\", \"refresh_token\", \"client_id\", \"scopes\"]\r\n      },\r\n      \"minItems\": 1\r\n    },\r\n\r\n    \"alerts\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Real-time alerts via ESI polling. Checks for changes at regular intervals.\",\r\n      \"properties\": {\r\n        \"enabled\": {\r\n          \"type\": \"boolean\",\r\n          \"default\": true\r\n        },\r\n        \"check_interval\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"Polling interval (e.g. '5m', '15m', '1h')\",\r\n          \"default\": \"5m\",\r\n          \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n        },\r\n        \"channels\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Which notification channels to use for alerts\",\r\n          \"items\": {\r\n            \"type\": \"string\",\r\n            \"enum\": [\"telegram\", \"discord\"]\r\n          }\r\n        },\r\n        \"rules\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Alert rules. Each rule defines a trigger type with optional thresholds.\",\r\n          \"items\": {\r\n            \"type\": \"object\",\r\n            \"properties\": {\r\n              \"type\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\r\n                  \"war_declared\",\r\n                  \"war_surrendered\",\r\n                  \"structure_fuel_low\",\r\n                  \"structure_under_attack\",\r\n                  \"skill_complete\",\r\n                  \"wallet_large_deposit\",\r\n                  \"wallet_large_withdrawal\",\r\n                  \"contract_expired\",\r\n                  \"industry_job_complete\",\r\n                  \"pi_extractor_expired\",\r\n                  \"clone_jump_available\",\r\n                  \"mail_received\",\r\n                  \"killmail\"\r\n                ],\r\n                \"description\": \"Alert type. Each type requires specific ESI scopes.\"\r\n              },\r\n              \"severity\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\"info\", \"warning\", \"critical\"],\r\n                \"default\": \"info\",\r\n                \"description\": \"Severity level — affects notification formatting and priority\"\r\n              },\r\n              \"threshold\": {\r\n                \"type\": \"number\",\r\n                \"description\": \"Numeric threshold (e.g. ISK amount for wallet alerts, fuel hours for structure alerts)\"\r\n              },\r\n              \"cooldown\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Minimum time between repeated alerts of the same type\",\r\n                \"default\": \"1h\",\r\n                \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n              },\r\n              \"character_filter\": {\r\n                \"type\": \"array\",\r\n                \"items\": { \"type\": \"integer\" },\r\n                \"description\": \"Only trigger for specific character IDs. Empty = all characters.\"\r\n              }\r\n            },\r\n            \"required\": [\"type\"]\r\n          }\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    },\r\n\r\n    \"reports\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Scheduled reports — generated and sent on a cron schedule.\",\r\n      \"properties\": {\r\n        \"enabled\": {\r\n          \"type\": \"boolean\",\r\n          \"default\": true\r\n        },\r\n        \"schedule\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"Cron expression (e.g. '0 9 * * *' = daily at 9am, '0 9,21 * * *' = 9am and 9pm)\",\r\n          \"default\": \"0 9 * * *\"\r\n        },\r\n        \"timezone\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"IANA timezone for the cron schedule\",\r\n          \"default\": \"Europe/Berlin\"\r\n        },\r\n        \"channels\": {\r\n          \"type\": \"array\",\r\n          \"items\": { \"type\": \"string\", \"enum\": [\"telegram\", \"discord\"] }\r\n        },\r\n        \"templates\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Which reports to generate\",\r\n          \"items\": {\r\n            \"type\": \"object\",\r\n            \"properties\": {\r\n              \"name\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\r\n                  \"net_worth\",\r\n                  \"skill_queue\",\r\n                  \"industry_jobs\",\r\n                  \"market_orders\",\r\n                  \"wallet_summary\",\r\n                  \"assets_summary\"\r\n                ],\r\n                \"description\": \"Report template name\"\r\n              },\r\n              \"format\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\"short\", \"detailed\"],\r\n                \"default\": \"short\",\r\n                \"description\": \"'short' = compact summary, 'detailed' = full report\"\r\n              },\r\n              \"character_filter\": {\r\n                \"type\": \"array\",\r\n                \"items\": { \"type\": \"integer\" },\r\n                \"description\": \"Only include specific character IDs. Empty = all characters.\"\r\n              }\r\n            },\r\n            \"required\": [\"name\"]\r\n          }\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    },\r\n\r\n    \"market\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Price tracking for items with threshold and trend alerts.\",\r\n      \"properties\": {\r\n        \"enabled\": {\r\n          \"type\": \"boolean\",\r\n          \"default\": true\r\n        },\r\n        \"check_interval\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"Polling interval for market prices\",\r\n          \"default\": \"30m\",\r\n          \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n        },\r\n        \"channels\": {\r\n          \"type\": \"array\",\r\n          \"items\": { \"type\": \"string\", \"enum\": [\"telegram\", \"discord\"] },\r\n          \"description\": \"Where to send market alerts. If empty, falls back to alerts.channels.\"\r\n        },\r\n        \"items\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Items to track with price thresholds\",\r\n          \"items\": {\r\n            \"type\": \"object\",\r\n            \"properties\": {\r\n              \"type_id\": {\r\n                \"type\": \"integer\",\r\n                \"description\": \"EVE Type ID (e.g. 44992 = PLEX). Resolve via /universe/types/{id}/\"\r\n              },\r\n              \"name\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Display name of the item\"\r\n              },\r\n              \"region_id\": {\r\n                \"type\": \"integer\",\r\n                \"description\": \"Region ID for market data\",\r\n                \"default\": 10000002\r\n              },\r\n              \"region_name\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Region display name\",\r\n                \"default\": \"The Forge\"\r\n              },\r\n              \"alert_above\": {\r\n                \"type\": \"number\",\r\n                \"description\": \"Alert when price exceeds this value (ISK)\"\r\n              },\r\n              \"alert_below\": {\r\n                \"type\": \"number\",\r\n                \"description\": \"Alert when price drops below this value (ISK)\"\r\n              },\r\n              \"trend_alert\": {\r\n                \"type\": \"object\",\r\n                \"description\": \"Percentage price change within a time window\",\r\n                \"properties\": {\r\n                  \"change_percent\": {\r\n                    \"type\": \"number\",\r\n                    \"description\": \"Percentage change that triggers an alert\",\r\n                    \"default\": 10\r\n                  },\r\n                  \"time_window\": {\r\n                    \"type\": \"string\",\r\n                    \"description\": \"Time window for trend calculation\",\r\n                    \"default\": \"1h\",\r\n                    \"pattern\": \"^[0-9]+(m|h|d)$\"\r\n                  }\r\n                }\r\n              },\r\n              \"cooldown\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Cooldown between market alerts for this item\",\r\n                \"default\": \"1h\",\r\n                \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n              }\r\n            },\r\n            \"required\": [\"type_id\", \"name\"]\r\n          }\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    }\r\n\r\n  },\r\n  \"required\": [\"schema_version\", \"characters\", \"notification_channels\"],\r\n  \"additionalProperties\": false\r\n}\n\nArchive v1.0.5: 11 files, 23504 bytes\n\nFiles: config/example-config.json (3738b), config/schema.json (11304b), README.md (5142b), references/authentication.md (4082b), references/endpoints.md (12013b), scripts/auth_flow.py (6321b), scripts/esi_query.py (4596b), scripts/get_token.py (3364b), scripts/validate_config.py (13527b), SKILL.md (10095b), _meta.json (126b)\n\nFile v1.0.5:SKILL.md\n\n---\r\nname: eve-esi\r\ndescription: \"Query and manage EVE Online characters via the ESI (EVE Swagger Interface) REST API. Use when the user asks about EVE Online character data, wallet balance, ISK transactions, assets, skill queue, skill points, clone locations, implants, fittings, contracts, market orders, mail, industry jobs, killmails, planetary interaction, loyalty points, or any other EVE account management task.\"\r\nenv:\r\n  - name: EVE_CLIENT_ID\r\n    description: \"EVE Developer Application Client ID (from https://developers.eveonline.com/applications). Optional: only needed if using $ENV: references in your dashboard config instead of passing --client-id to auth_flow.py directly.\"\r\n    required: false\r\n    sensitive: false\r\n  - name: EVE_TOKEN_MAIN\r\n    description: \"ESI OAuth2 access token for the main character. Optional: scripts auto-manage tokens via ~/.openclaw/eve-tokens.json (written by auth_flow.py). Only set this if using $ENV: references in your dashboard config.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: EVE_REFRESH_MAIN\r\n    description: \"ESI OAuth2 refresh token for automatic access token renewal. Optional: scripts auto-manage tokens via ~/.openclaw/eve-tokens.json. Only set this if using $ENV: references in your dashboard config.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: TELEGRAM_BOT_TOKEN\r\n    description: \"Telegram Bot API token for sending alerts and reports.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: TELEGRAM_CHAT_ID\r\n    description: \"Telegram chat ID where notifications are sent.\"\r\n    required: false\r\n    sensitive: false\r\n  - name: DISCORD_WEBHOOK_URL\r\n    description: \"Discord webhook URL for sending alerts and reports.\"\r\n    required: false\r\n    sensitive: true\r\n---\r\n\r\n# Data Handling\r\n\r\nThis skill communicates exclusively with the official EVE Online ESI API (`esi.evetech.net`) and EVE SSO (`login.eveonline.com`).\r\nNo character data is exfiltrated to third-party servers.\r\nOptional integrations (Telegram, Discord) are user-configured via environment variables and only transmit alerts defined by the user.\r\n\r\n# EVE Online ESI\r\n\r\nThe ESI (EVE Swagger Interface) is the official REST API for EVE Online third-party development.\r\n\r\n- Base URL: `https://esi.evetech.net/latest`\r\n- Spec: `https://esi.evetech.net/latest/swagger.json`\r\n- API Explorer: <https://developers.eveonline.com/api-explorer>\r\n\r\n## Skill Location\r\n\r\nAll scripts live at: `~/.openclaw/workspace/skills/eve-esi/scripts/`\r\n\r\nAlways use full paths when calling scripts:\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n```\r\n\r\n## Authentication\r\n\r\nTokens are stored in `~/.openclaw/eve-tokens.json` (created by auth_flow.py, chmod 600).\r\nAll scripts (`get_token.py`, `esi_query.py`) read from this file directly — **no env vars are required for normal operation.**\r\n\r\n**First-time setup** (once per character):\r\n```bash\r\n# 1. Set up SSH tunnel on your local PC:\r\n#    ssh -L 8080:127.0.0.1:8080 user@your-server -N\r\n# 2. Run auth flow on server (pass Client ID directly):\r\npython3 ~/.openclaw/workspace/skills/eve-esi/scripts/auth_flow.py --client-id <YOUR_CLIENT_ID> --char-name main\r\n# 3. Open the shown URL in browser, log in with EVE account\r\n```\r\n\r\n**Get a fresh access token** (tokens expire after ~20min, refresh is automatic):\r\n```bash\r\nTOKEN=$(python3 ~/.openclaw/workspace/skills/eve-esi/scripts/get_token.py --char main)\r\n```\r\n\r\n**List authenticated characters:**\r\n```bash\r\npython3 ~/.openclaw/workspace/skills/eve-esi/scripts/get_token.py --list\r\n```\r\n\r\nFor full OAuth2/PKCE details: see `references/authentication.md`.\r\n\r\n## Public endpoints (no auth)\r\n\r\n```bash\r\n# Character public info\r\ncurl -s \"https://esi.evetech.net/latest/characters/2114794365/\" | python -m json.tool\r\n\r\n# Portrait URLs\r\ncurl -s \"https://esi.evetech.net/latest/characters/2114794365/portrait/\"\r\n\r\n# Corporation history\r\ncurl -s \"https://esi.evetech.net/latest/characters/2114794365/corporationhistory/\"\r\n\r\n# Bulk affiliation lookup\r\ncurl -s -X POST \"https://esi.evetech.net/latest/characters/affiliation/\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[2114794365, 95538921]'\r\n```\r\n\r\n## Character info (authenticated)\r\n\r\n```bash\r\nTOKEN=\"<your_access_token>\"\r\nCHAR_ID=\"<your_character_id>\"\r\n\r\n# Online status (scope: esi-location.read_online.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/online/\"\r\n```\r\n\r\n## Wallet\r\n\r\n```bash\r\n# Balance (scope: esi-wallet.read_character_wallet.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/wallet/\"\r\n\r\n# Journal (paginated)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/wallet/journal/?page=1\"\r\n\r\n# Transactions\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/wallet/transactions/\"\r\n```\r\n\r\n## Assets\r\n\r\n```bash\r\n# All assets (paginated; scope: esi-assets.read_assets.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/assets/?page=1\"\r\n\r\n# Resolve item locations\r\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[1234567890, 9876543210]' \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/assets/locations/\"\r\n\r\n# Resolve item names\r\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[1234567890]' \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/assets/names/\"\r\n```\r\n\r\n## Skills\r\n\r\n```bash\r\n# All trained skills + total SP (scope: esi-skills.read_skills.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/skills/\"\r\n\r\n# Skill queue (scope: esi-skills.read_skillqueue.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/skillqueue/\"\r\n\r\n# Attributes (intelligence, memory, etc.)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/attributes/\"\r\n```\r\n\r\n## Location and ship\r\n\r\n```bash\r\n# Current location (scope: esi-location.read_location.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/location/\"\r\n\r\n# Current ship (scope: esi-location.read_ship_type.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/ship/\"\r\n```\r\n\r\n## Clones and implants\r\n\r\n```bash\r\n# Jump clones + home station (scope: esi-clones.read_clones.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/clones/\"\r\n\r\n# Active implants (scope: esi-clones.read_implants.v1)\r\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\r\n  \"https://esi.evetech.net/latest/characters/$CHAR_ID/implants/\"\r\n```\r\n\r\n## More endpoints\r\n\r\nFor contracts, fittings, mail, industry, killmails, market orders, mining, planetary interaction, loyalty points, notifications, blueprints, standings, and all other character endpoints, see [references/endpoints.md](references/endpoints.md).\r\n\r\n## Dashboard Config\r\n\r\nThe skill supports a modular dashboard config for alerts, reports, and market tracking. Each user defines what they need in a JSON config file.\r\n\r\n- **Schema**: [config/schema.json](config/schema.json) — full JSON Schema with all fields, types, and defaults\r\n- **Example**: [config/example-config.json](config/example-config.json) — ready-to-use template\r\n\r\n### Features\r\n\r\n| Module | Description |\r\n|--------|-------------|\r\n| **Alerts** | Real-time polling for war decs, structure attacks, skill completions, wallet changes, industry jobs, PI extractors, killmails, contracts, clone jumps, mail |\r\n| **Reports** | Cron-scheduled summaries: net worth, skill queue, industry, market orders, wallet, assets |\r\n| **Market** | Price tracking with absolute thresholds and trend detection |\r\n\r\n### Security\r\n\r\nTokens should **not** be stored in plain text. Use environment variable references:\r\n\r\n```json\r\n{\r\n  \"token\": \"$ENV:EVE_TOKEN_MAIN\",\r\n  \"refresh_token\": \"$ENV:EVE_REFRESH_MAIN\"\r\n}\r\n```\r\n\r\nThe config file should live outside the workspace (e.g. `~/.openclaw/eve-dashboard-config.json`).\r\n\r\n### Validate a config\r\n\r\n```bash\r\npython scripts/validate_config.py path/to/config.json\r\n\r\n# Show example config\r\npython scripts/validate_config.py --example\r\n\r\n# Show JSON schema\r\npython scripts/validate_config.py --schema\r\n```\r\n\r\n## Using the query script\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\nTOKEN=$(python3 $SKILL/scripts/get_token.py --char main)\r\nCHAR_ID=$(python3 $SKILL/scripts/get_token.py --char main --json | python3 -c \"import sys,json; print(json.load(sys.stdin))\" 2>/dev/null)\r\n\r\n# Simple query\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" --endpoint \"/characters/$CHAR_ID/wallet/\" --pretty\r\n\r\n# Fetch all pages of assets\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" --endpoint \"/characters/$CHAR_ID/assets/\" --pages --pretty\r\n\r\n# POST request (e.g. asset names)\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" --endpoint \"/characters/$CHAR_ID/assets/names/\" \\\r\n  --method POST --body '[1234567890]' --pretty\r\n```\r\n\r\n## Best practices\r\n\r\n- **Caching**: respect the `Expires` header; do not poll before it expires.\r\n- **Error limits**: monitor `X-ESI-Error-Limit-Remain`; back off when low.\r\n- **User-Agent**: always set a descriptive User-Agent with contact info.\r\n- **Rate limits**: some endpoints (mail, contracts) have internal rate limits returning HTTP 520.\r\n- **Pagination**: check the `X-Pages` response header; iterate with `?page=N`.\r\n- **Versioning**: use `/latest/` for current stable routes. `/dev/` may change without notice.\r\n\r\n## Resolving type IDs\r\n\r\nESI returns numeric type IDs (e.g. for ships, items, skills). Resolve names via:\r\n\r\n```bash\r\n# Single type\r\ncurl -s \"https://esi.evetech.net/latest/universe/types/587/\"\r\n\r\n# Bulk names (up to 1000 IDs)\r\ncurl -s -X POST \"https://esi.evetech.net/latest/universe/names/\" \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -d '[587, 638, 11393]'\r\n```\n\nFile v1.0.5:README.md\n\n# EVE ESI Skill for OpenClaw\r\n\r\nAn [OpenClaw](https://openclaw.ai) skill for interacting with the [EVE Online ESI API](https://developers.eveonline.com/api-explorer) (EVE Swagger Interface).\r\n\r\n## Features\r\n\r\n- **Authentication** — PKCE OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **ESI Queries** — reusable Python helper with pagination, error limits, and caching\r\n- **Multi-character** — store and manage tokens for multiple characters\r\n- **Dashboard Config** — modular alert/report/market-tracking config schema\r\n- **Reference docs** — full scope list, endpoint index, auth flow details\r\n\r\n## Structure\r\n\r\n```\r\neve-esi/\r\n├── SKILL.md                        # OpenClaw skill instructions\r\n├── README.md                       # This file\r\n├── scripts/\r\n│   ├── auth_flow.py                # One-time EVE SSO OAuth2 authentication\r\n│   ├── get_token.py                # Token refresh helper (auto-rotates)\r\n│   ├── esi_query.py                # ESI query helper with pagination\r\n│   └── validate_config.py          # Dashboard config validator\r\n├── config/\r\n│   ├── schema.json                 # JSON Schema for dashboard config\r\n│   └── example-config.json         # Ready-to-use template\r\n└── references/\r\n    ├── authentication.md           # EVE SSO OAuth2 + PKCE details\r\n    └── endpoints.md                # All character endpoints + scopes\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\ncd ~/.openclaw/workspace/skills\r\ngit clone https://github.com/burnshall-ui/openclaw-eve-skill eve-esi\r\n```\r\n\r\n## Authentication Setup\r\n\r\n**Prerequisites:**\r\n1. Register an app at [developers.eveonline.com](https://developers.eveonline.com/applications)\r\n2. Set callback URL to `http://127.0.0.1:8080/callback`\r\n3. Note your **Client ID**\r\n\r\n**One-time auth per character** (requires browser access):\r\n\r\n```bash\r\n# If on a remote server, set up an SSH tunnel first:\r\nssh -L 8080:127.0.0.1:8080 user@your-server -N\r\n\r\n# Run the auth flow:\r\npython3 scripts/auth_flow.py --client-id <YOUR_CLIENT_ID> --char-name main\r\n\r\n# Open the shown URL in your browser and log in with your EVE account\r\n```\r\n\r\nTokens are stored in `~/.openclaw/eve-tokens.json` (chmod 600).\r\n\r\n**Authenticate additional characters:**\r\n```bash\r\npython3 scripts/auth_flow.py --client-id <CLIENT_ID> --char-name alt1\r\n```\r\n\r\n## Quick Start\r\n\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n\r\n# Get a fresh access token (auto-refreshes on every call)\r\nTOKEN=$(python3 $SKILL/scripts/get_token.py --char main)\r\n\r\n# List all authenticated characters\r\npython3 $SKILL/scripts/get_token.py --list\r\n\r\n# Wallet balance\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" \\\r\n  --endpoint \"/characters/<CHAR_ID>/wallet/\" --pretty\r\n\r\n# Skill queue\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" \\\r\n  --endpoint \"/characters/<CHAR_ID>/skillqueue/\" --pretty\r\n\r\n# All assets (paginated)\r\npython3 $SKILL/scripts/esi_query.py --token \"$TOKEN\" \\\r\n  --endpoint \"/characters/<CHAR_ID>/assets/\" --pages --pretty\r\n```\r\n\r\n## Dashboard Config\r\n\r\nSet up automated alerts, scheduled reports, and market price tracking:\r\n\r\n```bash\r\n# Copy example config\r\ncp config/example-config.json ~/.openclaw/eve-dashboard-config.json\r\n\r\n# Edit with your character IDs and preferences\r\n# Use $ENV:VARIABLE_NAME for tokens — never store secrets in plain text\r\n\r\n# Validate\r\npython3 scripts/validate_config.py ~/.openclaw/eve-dashboard-config.json\r\n```\r\n\r\nSee [config/schema.json](config/schema.json) for the full schema.\r\n\r\n### Alert Types\r\n\r\n| Alert | Description |\r\n|-------|-------------|\r\n| `war_declared` | New war declaration against your corp |\r\n| `structure_under_attack` | Structure attacked |\r\n| `structure_fuel_low` | Fuel below threshold (hours) |\r\n| `skill_complete` | Skill training finished |\r\n| `wallet_large_deposit` | ISK deposit above threshold |\r\n| `industry_job_complete` | Manufacturing/research job done |\r\n| `pi_extractor_expired` | Planetary extraction head expired |\r\n| `killmail` | New killmail received |\r\n| `contract_expired` | Contract expired |\r\n\r\n### Report Templates\r\n\r\n| Report | Description |\r\n|--------|-------------|\r\n| `net_worth` | Total ISK across wallet + assets |\r\n| `skill_queue` | Current training status |\r\n| `industry_jobs` | Active manufacturing/research jobs |\r\n| `market_orders` | Open buy/sell orders |\r\n| `wallet_summary` | Recent transaction summary |\r\n| `assets_summary` | Top asset locations by value |\r\n\r\n## Security\r\n\r\n- Tokens stored in `~/.openclaw/eve-tokens.json` with `chmod 600`\r\n- Refresh tokens rotate on every use (EVE SSO best practice)\r\n- Dashboard config supports `$ENV:VARIABLE_NAME` to keep secrets out of files\r\n- Never commit `eve-tokens.json` or configs with real tokens\r\n\r\n## Requirements\r\n\r\n- Python 3.8+ (stdlib only — no pip dependencies)\r\n- OpenClaw gateway\r\n\r\n## Links\r\n\r\n- [EVE ESI API Explorer](https://developers.eveonline.com/api-explorer)\r\n- [EVE Developer Portal](https://developers.eveonline.com/applications)\r\n- [OpenClaw Docs](https://docs.openclaw.ai)\r\n- [ClawHub Skill Page](https://clawhub.ai/burnshall-ui/eve-esi)\n\nFile v1.0.5:_meta.json\n\n{\n  \"ownerId\": \"kn70krghga32ef4e3s75ew2vf980rh5b\",\n  \"slug\": \"eve-esi\",\n  \"version\": \"1.0.5\",\n  \"publishedAt\": 1771461710973\n}\n\nFile v1.0.5:references/authentication.md\n\n# EVE SSO OAuth2 Authentication\r\n\r\nEVE ESI uses OAuth 2.0 Authorization Code flow via EVE SSO (Single Sign-On).\r\n\r\nBase SSO URL: `https://login.eveonline.com`\r\n\r\n## Prerequisites\r\n\r\n1. Register an application at <https://developers.eveonline.com/applications>\r\n2. Note your **Client ID** and **Secret Key**\r\n3. Set a **Callback URL** (e.g. `http://localhost:8080/callback`)\r\n4. Select required **Scopes** for the endpoints you need\r\n\r\n## Authorization Code Flow\r\n\r\n### Step 1: Redirect user to SSO\r\n\r\n```\r\nhttps://login.eveonline.com/v2/oauth/authorize/?response_type=code&redirect_uri=<CALLBACK_URL>&client_id=<CLIENT_ID>&scope=<SCOPES>&state=<RANDOM_STATE>\r\n```\r\n\r\n- `scope`: space-separated list (e.g. `esi-wallet.read_character_wallet.v1 esi-assets.read_assets.v1`)\r\n- `state`: random string to prevent CSRF\r\n\r\n### Step 2: Exchange authorization code for tokens\r\n\r\n```bash\r\ncurl -X POST https://login.eveonline.com/v2/oauth/token \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"grant_type=authorization_code\" \\\r\n  -d \"code=<AUTH_CODE>\" \\\r\n  -d \"client_id=<CLIENT_ID>\" \\\r\n  -d \"code_verifier=<CODE_VERIFIER>\"\r\n```\r\n\r\nResponse:\r\n\r\n```json\r\n{\r\n  \"access_token\": \"eyJ...\",\r\n  \"expires_in\": 1199,\r\n  \"token_type\": \"Bearer\",\r\n  \"refresh_token\": \"abc123...\"\r\n}\r\n```\r\n\r\n### Step 3: Refresh expired tokens\r\n\r\nAccess tokens expire after ~20 minutes. Refresh with:\r\n\r\n```bash\r\ncurl -X POST https://login.eveonline.com/v2/oauth/token \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"grant_type=refresh_token\" \\\r\n  -d \"refresh_token=<REFRESH_TOKEN>\" \\\r\n  -d \"client_id=<CLIENT_ID>\"\r\n```\r\n\r\n### Step 4: Verify token and get character ID\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer <ACCESS_TOKEN>\" \\\r\n  https://login.eveonline.com/oauth/verify\r\n```\r\n\r\nResponse includes `CharacterID`, `CharacterName`, `Scopes`.\r\n\r\n## Using tokens with ESI\r\n\r\nPass the access token as a Bearer header:\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer <ACCESS_TOKEN>\" \\\r\n  \"https://esi.evetech.net/latest/characters/<CHARACTER_ID>/wallet/\"\r\n```\r\n\r\n## PKCE (Proof Key for Code Exchange)\r\n\r\nEVE SSO supports PKCE for public clients (no secret key). Generate a `code_verifier` (random 43-128 char string) and derive `code_challenge` via SHA-256:\r\n\r\n```python\r\nimport hashlib, base64, secrets\r\ncode_verifier = secrets.token_urlsafe(64)\r\ncode_challenge = base64.urlsafe_b64encode(\r\n    hashlib.sha256(code_verifier.encode()).digest()\r\n).rstrip(b\"=\").decode()\r\n```\r\n\r\nAdd `&code_challenge=<CHALLENGE>&code_challenge_method=S256` to the authorize URL. Include `code_verifier` in the token exchange.\r\n\r\n## Required Scopes by Category\r\n\r\n| Category | Scope |\r\n|----------|-------|\r\n| Wallet | `esi-wallet.read_character_wallet.v1` |\r\n| Assets | `esi-assets.read_assets.v1` |\r\n| Skills | `esi-skills.read_skills.v1`, `esi-skills.read_skillqueue.v1` |\r\n| Clones | `esi-clones.read_clones.v1`, `esi-clones.read_implants.v1` |\r\n| Location | `esi-location.read_location.v1`, `esi-location.read_ship_type.v1`, `esi-location.read_online.v1` |\r\n| Contacts | `esi-characters.read_contacts.v1` |\r\n| Contracts | `esi-contracts.read_character_contracts.v1` |\r\n| Fittings | `esi-fittings.read_fittings.v1` |\r\n| Mail | `esi-mail.read_mail.v1` |\r\n| Calendar | `esi-calendar.read_calendar_events.v1` |\r\n| Industry | `esi-industry.read_character_jobs.v1` |\r\n| Market Orders | `esi-markets.read_character_orders.v1` |\r\n| Killmails | `esi-killmails.read_killmails.v1` |\r\n| Blueprints | `esi-characters.read_blueprints.v1` |\r\n| Notifications | `esi-characters.read_notifications.v1` |\r\n| Bookmarks | `esi-bookmarks.read_character_bookmarks.v1` |\r\n| Loyalty | `esi-characters.read_loyalty.v1` |\r\n| Mining | `esi-industry.read_character_mining.v1` |\r\n| Roles | `esi-characters.read_corporation_roles.v1` |\r\n| Standings | `esi-characters.read_standings.v1` |\r\n| Fatigue | `esi-characters.read_fatigue.v1` |\r\n| Medals | `esi-characters.read_medals.v1` |\r\n| Titles | `esi-characters.read_titles.v1` |\r\n| Agent Research | `esi-characters.read_agents_research.v1` |\r\n| FW Stats | `esi-characters.read_fw_stats.v1` |\n\nFile v1.0.5:references/endpoints.md\n\n# EVE ESI Character Endpoints Reference\r\n\r\nBase URL: `https://esi.evetech.net/latest`\r\n\r\nAll authenticated endpoints require `Authorization: Bearer <TOKEN>` header. Replace `{character_id}` with the numeric character ID from SSO verify.\r\n\r\n## Table of Contents\r\n\r\n- [Character Info](#character-info)\r\n- [Wallet](#wallet)\r\n- [Assets](#assets)\r\n- [Skills](#skills)\r\n- [Clones and Implants](#clones-and-implants)\r\n- [Location](#location)\r\n- [Contacts](#contacts)\r\n- [Contracts](#contracts)\r\n- [Calendar](#calendar)\r\n- [Fittings](#fittings)\r\n- [Industry](#industry)\r\n- [Killmails](#killmails)\r\n- [Mail](#mail)\r\n- [Market Orders](#market-orders)\r\n- [Mining](#mining)\r\n- [Notifications](#notifications)\r\n- [Loyalty Points](#loyalty-points)\r\n- [Planets (PI)](#planets-pi)\r\n- [Blueprints](#blueprints)\r\n- [Roles and Titles](#roles-and-titles)\r\n- [Standings](#standings)\r\n- [Bookmarks](#bookmarks)\r\n- [Medals](#medals)\r\n- [Agent Research](#agent-research)\r\n- [Fatigue](#fatigue)\r\n- [Faction Warfare](#faction-warfare)\r\n- [Corporation History](#corporation-history)\r\n- [Portrait](#portrait)\r\n- [Search](#search)\r\n- [Fleet](#fleet)\r\n\r\n---\r\n\r\n## Character Info\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/` | -- | Public character info (name, corp, birthday, etc.) |\r\n| GET | `/characters/{character_id}/online/` | `esi-location.read_online.v1` | Online status, last login/logout |\r\n| POST | `/characters/affiliation/` | -- | Bulk lookup corp/alliance/faction for character IDs |\r\n\r\n## Wallet\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/wallet/` | `esi-wallet.read_character_wallet.v1` | ISK balance |\r\n| GET | `/characters/{character_id}/wallet/journal/` | `esi-wallet.read_character_wallet.v1` | Wallet journal (paginated) |\r\n| GET | `/characters/{character_id}/wallet/transactions/` | `esi-wallet.read_character_wallet.v1` | Wallet transactions |\r\n\r\n## Assets\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/assets/` | `esi-assets.read_assets.v1` | All assets (paginated) |\r\n| POST | `/characters/{character_id}/assets/locations/` | `esi-assets.read_assets.v1` | Locations for specific item IDs |\r\n| POST | `/characters/{character_id}/assets/names/` | `esi-assets.read_assets.v1` | Names for specific item IDs |\r\n\r\n## Skills\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/skills/` | `esi-skills.read_skills.v1` | All trained skills + total SP |\r\n| GET | `/characters/{character_id}/skillqueue/` | `esi-skills.read_skillqueue.v1` | Current skill queue |\r\n| GET | `/characters/{character_id}/attributes/` | `esi-skills.read_skills.v1` | Character attributes (int, mem, etc.) |\r\n\r\n## Clones and Implants\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/clones/` | `esi-clones.read_clones.v1` | Jump clones and home location |\r\n| GET | `/characters/{character_id}/implants/` | `esi-clones.read_implants.v1` | Active implant type IDs |\r\n\r\n## Location\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/location/` | `esi-location.read_location.v1` | Current solar system, station/structure |\r\n| GET | `/characters/{character_id}/ship/` | `esi-location.read_ship_type.v1` | Current ship type and name |\r\n\r\n## Contacts\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/contacts/` | `esi-characters.read_contacts.v1` | Contact list |\r\n| POST | `/characters/{character_id}/contacts/` | `esi-characters.write_contacts.v1` | Add contacts |\r\n| PUT | `/characters/{character_id}/contacts/` | `esi-characters.write_contacts.v1` | Edit contacts |\r\n| DELETE | `/characters/{character_id}/contacts/` | `esi-characters.write_contacts.v1` | Delete contacts |\r\n| GET | `/characters/{character_id}/contacts/labels/` | `esi-characters.read_contacts.v1` | Contact labels |\r\n\r\n## Contracts\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/contracts/` | `esi-contracts.read_character_contracts.v1` | All contracts (paginated) |\r\n| GET | `/characters/{character_id}/contracts/{contract_id}/bids/` | `esi-contracts.read_character_contracts.v1` | Bids on a contract |\r\n| GET | `/characters/{character_id}/contracts/{contract_id}/items/` | `esi-contracts.read_character_contracts.v1` | Items in a contract |\r\n\r\n## Calendar\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/calendar/` | `esi-calendar.read_calendar_events.v1` | Upcoming events (50 max) |\r\n| GET | `/characters/{character_id}/calendar/{event_id}/` | `esi-calendar.read_calendar_events.v1` | Event details |\r\n| GET | `/characters/{character_id}/calendar/{event_id}/attendees/` | `esi-calendar.read_calendar_events.v1` | Event attendees |\r\n| PUT | `/characters/{character_id}/calendar/{event_id}/` | `esi-calendar.respond_calendar_events.v1` | Respond to event |\r\n\r\n## Fittings\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fittings/` | `esi-fittings.read_fittings.v1` | Saved fittings |\r\n| POST | `/characters/{character_id}/fittings/` | `esi-fittings.write_fittings.v1` | Create a fitting |\r\n| DELETE | `/characters/{character_id}/fittings/{fitting_id}/` | `esi-fittings.write_fittings.v1` | Delete a fitting |\r\n\r\n## Industry\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/industry/jobs/` | `esi-industry.read_character_jobs.v1` | Industry jobs (manufacturing, research, etc.) |\r\n\r\n## Killmails\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/killmails/recent/` | `esi-killmails.read_killmails.v1` | Recent killmail IDs + hashes |\r\n| GET | `/killmails/{killmail_id}/{killmail_hash}/` | -- | Full killmail details (public) |\r\n\r\n## Mail\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/mail/` | `esi-mail.read_mail.v1` | Mail headers (paginated) |\r\n| GET | `/characters/{character_id}/mail/{mail_id}/` | `esi-mail.read_mail.v1` | Single mail body |\r\n| POST | `/characters/{character_id}/mail/` | `esi-mail.send_mail.v1` | Send a mail |\r\n| PUT | `/characters/{character_id}/mail/{mail_id}/` | `esi-mail.organize_mail.v1` | Update labels / mark read |\r\n| DELETE | `/characters/{character_id}/mail/{mail_id}/` | `esi-mail.organize_mail.v1` | Delete a mail |\r\n| GET | `/characters/{character_id}/mail/labels/` | `esi-mail.read_mail.v1` | Mail labels + unread counts |\r\n| POST | `/characters/{character_id}/mail/labels/` | `esi-mail.organize_mail.v1` | Create mail label |\r\n| GET | `/characters/{character_id}/mail/lists/` | `esi-mail.read_mail.v1` | Mailing lists |\r\n\r\n## Market Orders\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/orders/` | `esi-markets.read_character_orders.v1` | Active market orders |\r\n| GET | `/characters/{character_id}/orders/history/` | `esi-markets.read_character_orders.v1` | Expired/cancelled orders (paginated) |\r\n\r\n## Mining\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/mining/` | `esi-industry.read_character_mining.v1` | Mining ledger (last 30 days) |\r\n\r\n## Notifications\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/notifications/` | `esi-characters.read_notifications.v1` | All notifications |\r\n| GET | `/characters/{character_id}/notifications/contacts/` | `esi-characters.read_notifications.v1` | Contact notifications |\r\n\r\n## Loyalty Points\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/loyalty/points/` | `esi-characters.read_loyalty.v1` | LP balances per corp |\r\n\r\n## Planets (PI)\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/planets/` | `esi-planets.manage_planets.v1` | List of colonies |\r\n| GET | `/characters/{character_id}/planets/{planet_id}/` | `esi-planets.manage_planets.v1` | Colony layout and extractors |\r\n\r\n## Blueprints\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/blueprints/` | `esi-characters.read_blueprints.v1` | All blueprints (paginated) |\r\n\r\n## Roles and Titles\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/roles/` | `esi-characters.read_corporation_roles.v1` | Corporation roles |\r\n| GET | `/characters/{character_id}/titles/` | `esi-characters.read_titles.v1` | Corporation titles |\r\n\r\n## Standings\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/standings/` | `esi-characters.read_standings.v1` | NPC standings |\r\n\r\n## Bookmarks\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/bookmarks/` | `esi-bookmarks.read_character_bookmarks.v1` | All bookmarks (paginated) |\r\n| GET | `/characters/{character_id}/bookmarks/folders/` | `esi-bookmarks.read_character_bookmarks.v1` | Bookmark folders |\r\n\r\n## Medals\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/medals/` | `esi-characters.read_medals.v1` | Awarded medals |\r\n\r\n## Agent Research\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/agents_research/` | `esi-characters.read_agents_research.v1` | Research agents and points |\r\n\r\n## Fatigue\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fatigue/` | `esi-characters.read_fatigue.v1` | Jump fatigue expiry timestamps |\r\n\r\n## Faction Warfare\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fw/stats/` | `esi-characters.read_fw_stats.v1` | FW kill/VP stats |\r\n\r\n## Corporation History\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/corporationhistory/` | -- | Public employment history |\r\n\r\n## Portrait\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/portrait/` | -- | Portrait URLs (64/128/256/512px) |\r\n\r\n## Search\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/search/` | `esi-search.search_structures.v1` | Authenticated search (includes structures) |\r\n\r\n## Fleet\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/fleet/` | `esi-fleets.read_fleet.v1` | Current fleet info |\r\n\r\n---\r\n\r\n## Pagination\r\n\r\nPaginated endpoints return `X-Pages` header. Append `?page=N` (1-based). Always check `X-Pages` to determine total pages.\r\n\r\n## Caching\r\n\r\nEvery response includes `Expires` and `Last-Modified` headers. Do not request again before `Expires`. Use `If-None-Match` with the `ETag` header for conditional requests (returns 304 if unchanged).\r\n\r\n## Error Handling\r\n\r\n- `403`: Missing scope or wrong character\r\n- `404`: Resource not found\r\n- `420`: Error rate limited (back off and retry)\r\n- `502/503/504`: Upstream server issue (retry with backoff)\r\n- Check `X-ESI-Error-Limit-Remain` and `X-ESI-Error-Limit-Reset` headers\n\nFile v1.0.5:config/example-config.json\n\n{\r\n  \"schema_version\": \"1.0\",\r\n\r\n  \"notification_channels\": {\r\n    \"telegram\": {\r\n      \"bot_token\": \"$ENV:TELEGRAM_BOT_TOKEN\",\r\n      \"chat_id\": \"$ENV:TELEGRAM_CHAT_ID\"\r\n    }\r\n  },\r\n\r\n  \"characters\": [\r\n    {\r\n      \"id\": 2114794365,\r\n      \"name\": \"Main Character\",\r\n      \"token\": \"$ENV:EVE_TOKEN_MAIN\",\r\n      \"refresh_token\": \"$ENV:EVE_REFRESH_MAIN\",\r\n      \"client_id\": \"$ENV:EVE_CLIENT_ID\",\r\n      \"scopes\": [\r\n        \"esi-wallet.read_character_wallet.v1\",\r\n        \"esi-skills.read_skills.v1\",\r\n        \"esi-skills.read_skillqueue.v1\",\r\n        \"esi-assets.read_assets.v1\",\r\n        \"esi-clones.read_clones.v1\",\r\n        \"esi-clones.read_implants.v1\",\r\n        \"esi-location.read_location.v1\",\r\n        \"esi-location.read_ship_type.v1\",\r\n        \"esi-location.read_online.v1\",\r\n        \"esi-characters.read_notifications.v1\",\r\n        \"esi-industry.read_character_jobs.v1\",\r\n        \"esi-markets.read_character_orders.v1\",\r\n        \"esi-contracts.read_character_contracts.v1\",\r\n        \"esi-killmails.read_killmails.v1\",\r\n        \"esi-planets.manage_planets.v1\",\r\n        \"esi-characters.read_fatigue.v1\",\r\n        \"esi-mail.read_mail.v1\"\r\n      ],\r\n      \"corporation\": {\r\n        \"id\": 98000001,\r\n        \"name\": \"My Corp\"\r\n      },\r\n      \"enabled\": true\r\n    }\r\n  ],\r\n\r\n  \"alerts\": {\r\n    \"enabled\": true,\r\n    \"check_interval\": \"5m\",\r\n    \"channels\": [\"telegram\"],\r\n    \"rules\": [\r\n      {\r\n        \"type\": \"war_declared\",\r\n        \"severity\": \"critical\"\r\n      },\r\n      {\r\n        \"type\": \"structure_under_attack\",\r\n        \"severity\": \"critical\"\r\n      },\r\n      {\r\n        \"type\": \"structure_fuel_low\",\r\n        \"severity\": \"warning\",\r\n        \"threshold\": 24\r\n      },\r\n      {\r\n        \"type\": \"skill_complete\",\r\n        \"severity\": \"info\",\r\n        \"cooldown\": \"1h\"\r\n      },\r\n      {\r\n        \"type\": \"wallet_large_deposit\",\r\n        \"severity\": \"info\",\r\n        \"threshold\": 1000000000\r\n      },\r\n      {\r\n        \"type\": \"industry_job_complete\",\r\n        \"severity\": \"info\",\r\n        \"cooldown\": \"30m\"\r\n      },\r\n      {\r\n        \"type\": \"pi_extractor_expired\",\r\n        \"severity\": \"warning\"\r\n      },\r\n      {\r\n        \"type\": \"killmail\",\r\n        \"severity\": \"info\"\r\n      },\r\n      {\r\n        \"type\": \"contract_expired\",\r\n        \"severity\": \"warning\",\r\n        \"cooldown\": \"2h\"\r\n      }\r\n    ]\r\n  },\r\n\r\n  \"reports\": {\r\n    \"enabled\": true,\r\n    \"schedule\": \"0 9,21 * * *\",\r\n    \"timezone\": \"Europe/Berlin\",\r\n    \"channels\": [\"telegram\"],\r\n    \"templates\": [\r\n      {\r\n        \"name\": \"net_worth\",\r\n        \"format\": \"short\"\r\n      },\r\n      {\r\n        \"name\": \"skill_queue\",\r\n        \"format\": \"detailed\"\r\n      },\r\n      {\r\n        \"name\": \"wallet_summary\",\r\n        \"format\": \"short\"\r\n      },\r\n      {\r\n        \"name\": \"assets_summary\",\r\n        \"format\": \"short\"\r\n      }\r\n    ]\r\n  },\r\n\r\n  \"market\": {\r\n    \"enabled\": true,\r\n    \"check_interval\": \"30m\",\r\n    \"channels\": [\"telegram\"],\r\n    \"items\": [\r\n      {\r\n        \"type_id\": 44992,\r\n        \"name\": \"PLEX\",\r\n        \"region_id\": 10000002,\r\n        \"region_name\": \"The Forge\",\r\n        \"alert_above\": 4500000,\r\n        \"alert_below\": 3500000,\r\n        \"trend_alert\": {\r\n          \"change_percent\": 10,\r\n          \"time_window\": \"1h\"\r\n        },\r\n        \"cooldown\": \"1h\"\r\n      },\r\n      {\r\n        \"type_id\": 34,\r\n        \"name\": \"Tritanium\",\r\n        \"region_id\": 10000002,\r\n        \"region_name\": \"The Forge\",\r\n        \"trend_alert\": {\r\n          \"change_percent\": 15,\r\n          \"time_window\": \"6h\"\r\n        }\r\n      },\r\n      {\r\n        \"type_id\": 16274,\r\n        \"name\": \"Skill Injector\",\r\n        \"region_id\": 10000002,\r\n        \"region_name\": \"The Forge\",\r\n        \"alert_below\": 800000000,\r\n        \"cooldown\": \"2h\"\r\n      }\r\n    ]\r\n  }\r\n}\n\nFile v1.0.5:config/schema.json\n\n{\r\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\r\n  \"title\": \"EVE Dashboard Config\",\r\n  \"description\": \"Modular config schema for the EVE Command Center. Each user configures which alerts, reports, and market trackers they need.\",\r\n  \"type\": \"object\",\r\n  \"properties\": {\r\n\r\n    \"schema_version\": {\r\n      \"type\": \"string\",\r\n      \"description\": \"Schema version for future migrations\",\r\n      \"default\": \"1.0\",\r\n      \"enum\": [\"1.0\"]\r\n    },\r\n\r\n    \"notification_channels\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Connection details for notification channels. Values can be literal or $ENV:VARIABLE_NAME references.\",\r\n      \"properties\": {\r\n        \"telegram\": {\r\n          \"type\": \"object\",\r\n          \"properties\": {\r\n            \"bot_token\": {\r\n              \"type\": \"string\",\r\n              \"description\": \"Telegram Bot Token (e.g. '123456:ABC-DEF...' or '$ENV:TELEGRAM_BOT_TOKEN')\"\r\n            },\r\n            \"chat_id\": {\r\n              \"type\": \"string\",\r\n              \"description\": \"Telegram Chat ID (e.g. '-100123456789' or '$ENV:TELEGRAM_CHAT_ID')\"\r\n            }\r\n          },\r\n          \"required\": [\"bot_token\", \"chat_id\"]\r\n        },\r\n        \"discord\": {\r\n          \"type\": \"object\",\r\n          \"properties\": {\r\n            \"webhook_url\": {\r\n              \"type\": \"string\",\r\n              \"description\": \"Discord Webhook URL (or '$ENV:DISCORD_WEBHOOK_URL')\"\r\n            }\r\n          },\r\n          \"required\": [\"webhook_url\"]\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    },\r\n\r\n    \"characters\": {\r\n      \"type\": \"array\",\r\n      \"description\": \"EVE characters to monitor, with auth tokens and granted scopes\",\r\n      \"items\": {\r\n        \"type\": \"object\",\r\n        \"properties\": {\r\n          \"id\": {\r\n            \"type\": \"integer\",\r\n            \"description\": \"EVE Character ID (from SSO /oauth/verify)\"\r\n          },\r\n          \"name\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"Display name (optional, for readability)\"\r\n          },\r\n          \"token\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"ESI Access Token (or '$ENV:EVE_TOKEN_MAIN'). Expires after ~20min.\"\r\n          },\r\n          \"refresh_token\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"ESI Refresh Token for automatic renewal (or '$ENV:EVE_REFRESH_MAIN')\"\r\n          },\r\n          \"client_id\": {\r\n            \"type\": \"string\",\r\n            \"description\": \"EVE Developer App Client ID (or '$ENV:EVE_CLIENT_ID')\"\r\n          },\r\n          \"scopes\": {\r\n            \"type\": \"array\",\r\n            \"description\": \"List of granted ESI scopes. Validated against required scopes during config check.\",\r\n            \"items\": {\r\n              \"type\": \"string\"\r\n            },\r\n            \"examples\": [\r\n              [\"esi-wallet.read_character_wallet.v1\", \"esi-skills.read_skills.v1\", \"esi-skills.read_skillqueue.v1\"]\r\n            ]\r\n          },\r\n          \"corporation\": {\r\n            \"type\": \"object\",\r\n            \"description\": \"Corporation association (optional, otherwise derived from ESI)\",\r\n            \"properties\": {\r\n              \"id\": { \"type\": \"integer\" },\r\n              \"name\": { \"type\": \"string\" }\r\n            }\r\n          },\r\n          \"enabled\": {\r\n            \"type\": \"boolean\",\r\n            \"description\": \"Whether to actively monitor this character\",\r\n            \"default\": true\r\n          }\r\n        },\r\n        \"required\": [\"id\", \"token\", \"refresh_token\", \"client_id\", \"scopes\"]\r\n      },\r\n      \"minItems\": 1\r\n    },\r\n\r\n    \"alerts\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Real-time alerts via ESI polling. Checks for changes at regular intervals.\",\r\n      \"properties\": {\r\n        \"enabled\": {\r\n          \"type\": \"boolean\",\r\n          \"default\": true\r\n        },\r\n        \"check_interval\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"Polling interval (e.g. '5m', '15m', '1h')\",\r\n          \"default\": \"5m\",\r\n          \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n        },\r\n        \"channels\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Which notification channels to use for alerts\",\r\n          \"items\": {\r\n            \"type\": \"string\",\r\n            \"enum\": [\"telegram\", \"discord\"]\r\n          }\r\n        },\r\n        \"rules\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Alert rules. Each rule defines a trigger type with optional thresholds.\",\r\n          \"items\": {\r\n            \"type\": \"object\",\r\n            \"properties\": {\r\n              \"type\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\r\n                  \"war_declared\",\r\n                  \"war_surrendered\",\r\n                  \"structure_fuel_low\",\r\n                  \"structure_under_attack\",\r\n                  \"skill_complete\",\r\n                  \"wallet_large_deposit\",\r\n                  \"wallet_large_withdrawal\",\r\n                  \"contract_expired\",\r\n                  \"industry_job_complete\",\r\n                  \"pi_extractor_expired\",\r\n                  \"clone_jump_available\",\r\n                  \"mail_received\",\r\n                  \"killmail\"\r\n                ],\r\n                \"description\": \"Alert type. Each type requires specific ESI scopes.\"\r\n              },\r\n              \"severity\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\"info\", \"warning\", \"critical\"],\r\n                \"default\": \"info\",\r\n                \"description\": \"Severity level — affects notification formatting and priority\"\r\n              },\r\n              \"threshold\": {\r\n                \"type\": \"number\",\r\n                \"description\": \"Numeric threshold (e.g. ISK amount for wallet alerts, fuel hours for structure alerts)\"\r\n              },\r\n              \"cooldown\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Minimum time between repeated alerts of the same type\",\r\n                \"default\": \"1h\",\r\n                \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n              },\r\n              \"character_filter\": {\r\n                \"type\": \"array\",\r\n                \"items\": { \"type\": \"integer\" },\r\n                \"description\": \"Only trigger for specific character IDs. Empty = all characters.\"\r\n              }\r\n            },\r\n            \"required\": [\"type\"]\r\n          }\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    },\r\n\r\n    \"reports\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Scheduled reports — generated and sent on a cron schedule.\",\r\n      \"properties\": {\r\n        \"enabled\": {\r\n          \"type\": \"boolean\",\r\n          \"default\": true\r\n        },\r\n        \"schedule\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"Cron expression (e.g. '0 9 * * *' = daily at 9am, '0 9,21 * * *' = 9am and 9pm)\",\r\n          \"default\": \"0 9 * * *\"\r\n        },\r\n        \"timezone\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"IANA timezone for the cron schedule\",\r\n          \"default\": \"Europe/Berlin\"\r\n        },\r\n        \"channels\": {\r\n          \"type\": \"array\",\r\n          \"items\": { \"type\": \"string\", \"enum\": [\"telegram\", \"discord\"] }\r\n        },\r\n        \"templates\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Which reports to generate\",\r\n          \"items\": {\r\n            \"type\": \"object\",\r\n            \"properties\": {\r\n              \"name\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\r\n                  \"net_worth\",\r\n                  \"skill_queue\",\r\n                  \"industry_jobs\",\r\n                  \"market_orders\",\r\n                  \"wallet_summary\",\r\n                  \"assets_summary\"\r\n                ],\r\n                \"description\": \"Report template name\"\r\n              },\r\n              \"format\": {\r\n                \"type\": \"string\",\r\n                \"enum\": [\"short\", \"detailed\"],\r\n                \"default\": \"short\",\r\n                \"description\": \"'short' = compact summary, 'detailed' = full report\"\r\n              },\r\n              \"character_filter\": {\r\n                \"type\": \"array\",\r\n                \"items\": { \"type\": \"integer\" },\r\n                \"description\": \"Only include specific character IDs. Empty = all characters.\"\r\n              }\r\n            },\r\n            \"required\": [\"name\"]\r\n          }\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    },\r\n\r\n    \"market\": {\r\n      \"type\": \"object\",\r\n      \"description\": \"Price tracking for items with threshold and trend alerts.\",\r\n      \"properties\": {\r\n        \"enabled\": {\r\n          \"type\": \"boolean\",\r\n          \"default\": true\r\n        },\r\n        \"check_interval\": {\r\n          \"type\": \"string\",\r\n          \"description\": \"Polling interval for market prices\",\r\n          \"default\": \"30m\",\r\n          \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n        },\r\n        \"channels\": {\r\n          \"type\": \"array\",\r\n          \"items\": { \"type\": \"string\", \"enum\": [\"telegram\", \"discord\"] },\r\n          \"description\": \"Where to send market alerts. If empty, falls back to alerts.channels.\"\r\n        },\r\n        \"items\": {\r\n          \"type\": \"array\",\r\n          \"description\": \"Items to track with price thresholds\",\r\n          \"items\": {\r\n            \"type\": \"object\",\r\n            \"properties\": {\r\n              \"type_id\": {\r\n                \"type\": \"integer\",\r\n                \"description\": \"EVE Type ID (e.g. 44992 = PLEX). Resolve via /universe/types/{id}/\"\r\n              },\r\n              \"name\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Display name of the item\"\r\n              },\r\n              \"region_id\": {\r\n                \"type\": \"integer\",\r\n                \"description\": \"Region ID for market data\",\r\n                \"default\": 10000002\r\n              },\r\n              \"region_name\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Region display name\",\r\n                \"default\": \"The Forge\"\r\n              },\r\n              \"alert_above\": {\r\n                \"type\": \"number\",\r\n                \"description\": \"Alert when price exceeds this value (ISK)\"\r\n              },\r\n              \"alert_below\": {\r\n                \"type\": \"number\",\r\n                \"description\": \"Alert when price drops below this value (ISK)\"\r\n              },\r\n              \"trend_alert\": {\r\n                \"type\": \"object\",\r\n                \"description\": \"Percentage price change within a time window\",\r\n                \"properties\": {\r\n                  \"change_percent\": {\r\n                    \"type\": \"number\",\r\n                    \"description\": \"Percentage change that triggers an alert\",\r\n                    \"default\": 10\r\n                  },\r\n                  \"time_window\": {\r\n                    \"type\": \"string\",\r\n                    \"description\": \"Time window for trend calculation\",\r\n                    \"default\": \"1h\",\r\n                    \"pattern\": \"^[0-9]+(m|h|d)$\"\r\n                  }\r\n                }\r\n              },\r\n              \"cooldown\": {\r\n                \"type\": \"string\",\r\n                \"description\": \"Cooldown between market alerts for this item\",\r\n                \"default\": \"1h\",\r\n                \"pattern\": \"^[0-9]+(s|m|h)$\"\r\n              }\r\n            },\r\n            \"required\": [\"type_id\", \"name\"]\r\n          }\r\n        }\r\n      },\r\n      \"additionalProperties\": false\r\n    }\r\n\r\n  },\r\n  \"required\": [\"schema_version\", \"characters\", \"notification_channels\"],\r\n  \"additionalProperties\": false\r\n}","readmeExcerpt":"Skill: Eve online Esi Skill Owner: burnshall-ui Summary: Query and manage EVE Online characters via the ESI (EVE Swagger Interface) REST API. Use when the user asks about EVE Online character data, wallet balance,... Tags: latest:1.0.5 Version history: v1.0.6 | 2026-02-22T02:44:47.485Z | user eve-esi 1.0.6 - Added .gitignore for better repository hygiene. - Introduced config/esi_endpoints.json for improved endpoint o","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"File v1.0.6:README.md\n\n# EVE ESI Skill for OpenClaw\r\n\r\nAn [OpenClaw](https://openclaw.ai) skill for interacting with the [EVE Online ESI API](https://developers.eveonline.com/api-explorer) (EVE Swagger Interface).\r\n\r\n## Features\r\n\r\n<<<<<<< HEAD\r\n- **PKCE Authentication** — Secure OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **Multi-Character** — Store and manage tokens for unlimited characters\r\n- **PI Monitoring** — Planetary Interaction status, extractor timers, storage fill levels\r\n- **Market Prices** — Global average prices and Jita buy/sell lookups\r\n- **ESI Queries** — Reusable Python helper with pagination, rate-limit handling, and error recovery\r\n- **Threat Assessment** — System threat scoring using ESI kills/jumps + zKillboard PVP data\r\n- **Route Planning** — Annotated routes with per-system threat levels\r\n- **Dashboard Config** — Modular alert/report/market-tracking config with JSON Schema\r\n=======\r\n- **Authentication** — PKCE OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **ESI Queries** — reusable Python helper with pagination, error limits, and caching\r\n- **PI + Market Actions** — built-in actions for PI planet status and Jita price snapshots\r\n- **Multi-character** — store and manage tokens for multiple characters\r\n- **Dashboard Config** — modular alert/report/market-tracking config schema\r\n- **Reference docs** — full scope list, endpoint index, auth flow details\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n\r\n## Structure"},{"language":"text","snippet":"File v1.0.5:README.md\n\n# EVE ESI Skill for OpenClaw\r\n\r\nAn [OpenClaw](https://openclaw.ai) skill for interacting with the [EVE Online ESI API](https://developers.eveonline.com/api-explorer) (EVE Swagger Interface).\r\n\r\n## Features\r\n\r\n- **Authentication** — PKCE OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **ESI Queries** — reusable Python helper with pagination, error limits, and caching\r\n- **Multi-character** — store and manage tokens for multiple characters\r\n- **Dashboard Config** — modular alert/report/market-tracking config schema\r\n- **Reference docs** — full scope list, endpoint index, auth flow details\r\n\r\n## Structure"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\r\nname: eve-esi\r\ndescription: \"Query and manage EVE Online characters via the ESI (EVE Swagger Interface) REST API. Use when the user asks about EVE Online character data, wallet balance, ISK transactions, assets, skill queue, skill points, clone locations, implants, fittings, contracts, market orders, mail, industry jobs, killmails, planetary interaction, loyalty points, or any other EVE account management task.\"\r\nenv:\r\n  - name: EVE_CLIENT_ID\r\n    description: \"EVE Developer Application Client ID (from https://developers.eveonline.com/applications). Optional: only needed if using $ENV: references in your dashboard config instead of passing --client-id to auth_flow.py directly.\"\r\n    required: false\r\n    sensitive: false\r\n  - name: EVE_TOKEN_MAIN\r\n    description: \"ESI OAuth2 access token for the main character. Optional: scripts auto-manage tokens via ~/.openclaw/eve-tokens.json (written by auth_flow.py). Only set this if using $ENV: references in your dashboard config.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: EVE_REFRESH_MAIN\r\n    description: \"ESI OAuth2 refresh token for automatic access token renewal. Optional: scripts auto-manage tokens via ~/.openclaw/eve-tokens.json. Only set this if using $ENV: references in your dashboard config.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: TELEGRAM_BOT_TOKEN\r\n    description: \"Telegram Bot API token for sending alerts and reports.\"\r\n    required: false\r\n    sensitive: true\r\n  - name: TELEGRAM_CHAT_ID\r\n    description: \"Telegram chat ID where notifications are sent.\"\r\n    required: false\r\n    sensitive: false\r\n  - name: DISCORD_WEBHOOK_URL\r\n    description: \"Discord webhook URL for sending alerts and reports.\"\r\n    required: false\r\n    sensitive: true\r\n---\r\n\r\n# Data Handling\r\n\r\nThis skill communicates exclusively with the official EVE Online ESI API (`esi.evetech.net`) and EVE SSO (`login.eveonline.com`).\r\nNo character data is exfiltrated to third-party servers.\r\nOptional integrations (Telegram, Discord) are user-configured via environment variables and only transmit alerts defined by the user.\r\n\r\n# EVE Online ESI\r\n\r\nThe ESI (EVE Swagger Interface) is the official REST API for EVE Online third-party development.\r\n\r\n- Base URL: `https://esi.evetech.net/latest`\r\n- Spec: `https://esi.evetech.net/latest/swagger.json`\r\n- API Explorer: <https://developers.eveonline.com/api-explorer>\r\n\r\n## Skill Location\r\n\r\nAll scripts live at: `~/.openclaw/workspace/skills/eve-esi/scripts/`\r\n\r\nAlways use full paths when calling scripts:\r\n```bash\r\nSKILL=~/.openclaw/workspace/skills/eve-esi\r\n```\r\n\r\n## Authentication\r\n\r\nTokens are stored in `~/.openclaw/eve-tokens.json` (created by auth_flow.py, chmod 600).\r\nAll scripts (`get_token.py`, `esi_query.py`) read from this file directly — **no env vars are required for normal operation.**\r\n\r\n**First-time setup** (once per character):\r\n```bash\r\n# 1. Set up SSH tunnel on your local PC:\r\n#    ssh -L 8080:127.0.0.1:8080 user@your-server -N\r\n# 2. Run auth flow on "},{"path":"README.md","content":"# EVE ESI Skill for OpenClaw\r\n\r\nAn [OpenClaw](https://openclaw.ai) skill for interacting with the [EVE Online ESI API](https://developers.eveonline.com/api-explorer) (EVE Swagger Interface).\r\n\r\n## Features\r\n\r\n<<<<<<< HEAD\r\n- **PKCE Authentication** — Secure OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **Multi-Character** — Store and manage tokens for unlimited characters\r\n- **PI Monitoring** — Planetary Interaction status, extractor timers, storage fill levels\r\n- **Market Prices** — Global average prices and Jita buy/sell lookups\r\n- **ESI Queries** — Reusable Python helper with pagination, rate-limit handling, and error recovery\r\n- **Threat Assessment** — System threat scoring using ESI kills/jumps + zKillboard PVP data\r\n- **Route Planning** — Annotated routes with per-system threat levels\r\n- **Dashboard Config** — Modular alert/report/market-tracking config with JSON Schema\r\n=======\r\n- **Authentication** — PKCE OAuth2 flow via EVE SSO, auto-refreshing tokens\r\n- **ESI Queries** — reusable Python helper with pagination, error limits, and caching\r\n- **PI + Market Actions** — built-in actions for PI planet status and Jita price snapshots\r\n- **Multi-character** — store and manage tokens for multiple characters\r\n- **Dashboard Config** — modular alert/report/market-tracking config schema\r\n- **Reference docs** — full scope list, endpoint index, auth flow details\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n\r\n## Structure\r\n\r\n```\r\neve-esi/\r\n├── SKILL.md                        # OpenClaw skill instructions (loaded by agent)\r\n├── README.md                       # This file\r\n├── .gitignore                      # Prevents token/secret commits\r\n├── scripts/\r\n<<<<<<< HEAD\r\n│   ├── auth_flow.py                # One-time EVE SSO OAuth2 PKCE authentication\r\n│   ├── get_token.py                # Token refresh helper (auto-rotates on every use)\r\n=======\r\n│   ├── auth_flow.py                # One-time EVE SSO OAuth2 authentication\r\n│   ├── get_token.py                # Token refresh helper (auto-rotates)\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n│   ├── esi_query.py                # ESI query helper + high-level PI/market actions\r\n│   └── validate_config.py          # Dashboard config validator\r\n├── config/\r\n│   ├── schema.json                 # JSON Schema for dashboard config\r\n│   ├── example-config.json         # Ready-to-use template\r\n<<<<<<< HEAD\r\n│   └── esi_endpoints.json          # PI and market endpoint definitions\r\n=======\r\n│   └── esi_endpoints.json          # Endpoint catalog (PI + market helpers)\r\n>>>>>>> 37636f5 (docs: update README for PI action workflow)\r\n└── references/\r\n    ├── authentication.md           # EVE SSO OAuth2 + PKCE details\r\n    └── endpoints.md                # All character endpoints + scopes\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\ncd ~/.openclaw/workspace/skills\r\ngit clone https://github.com/burnshall-ui/openclaw-eve-skill eve-esi\r\n```\r\n\r\nNo pip dependencies — uses Python 3.8+ stdlib only.\r\n\r\n"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn70krghga32ef4e3s75ew2vf980rh5b\",\n  \"slug\": \"eve-esi\",\n  \"version\": \"1.0.6\",\n  \"publishedAt\": 1771728287485\n}"},{"path":"references/authentication.md","content":"# EVE SSO OAuth2 Authentication\r\n\r\nEVE ESI uses OAuth 2.0 Authorization Code flow via EVE SSO (Single Sign-On).\r\n\r\nBase SSO URL: `https://login.eveonline.com`\r\n\r\n## Prerequisites\r\n\r\n1. Register an application at <https://developers.eveonline.com/applications>\r\n2. Note your **Client ID** and **Secret Key**\r\n3. Set a **Callback URL** (e.g. `http://localhost:8080/callback`)\r\n4. Select required **Scopes** for the endpoints you need\r\n\r\n## Authorization Code Flow\r\n\r\n### Step 1: Redirect user to SSO\r\n\r\n```\r\nhttps://login.eveonline.com/v2/oauth/authorize/?response_type=code&redirect_uri=<CALLBACK_URL>&client_id=<CLIENT_ID>&scope=<SCOPES>&state=<RANDOM_STATE>\r\n```\r\n\r\n- `scope`: space-separated list (e.g. `esi-wallet.read_character_wallet.v1 esi-assets.read_assets.v1`)\r\n- `state`: random string to prevent CSRF\r\n\r\n### Step 2: Exchange authorization code for tokens\r\n\r\n```bash\r\ncurl -X POST https://login.eveonline.com/v2/oauth/token \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"grant_type=authorization_code\" \\\r\n  -d \"code=<AUTH_CODE>\" \\\r\n  -d \"client_id=<CLIENT_ID>\" \\\r\n  -d \"code_verifier=<CODE_VERIFIER>\"\r\n```\r\n\r\nResponse:\r\n\r\n```json\r\n{\r\n  \"access_token\": \"eyJ...\",\r\n  \"expires_in\": 1199,\r\n  \"token_type\": \"Bearer\",\r\n  \"refresh_token\": \"abc123...\"\r\n}\r\n```\r\n\r\n### Step 3: Refresh expired tokens\r\n\r\nAccess tokens expire after ~20 minutes. Refresh with:\r\n\r\n```bash\r\ncurl -X POST https://login.eveonline.com/v2/oauth/token \\\r\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\r\n  -d \"grant_type=refresh_token\" \\\r\n  -d \"refresh_token=<REFRESH_TOKEN>\" \\\r\n  -d \"client_id=<CLIENT_ID>\"\r\n```\r\n\r\n### Step 4: Verify token and get character ID\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer <ACCESS_TOKEN>\" \\\r\n  https://login.eveonline.com/oauth/verify\r\n```\r\n\r\nResponse includes `CharacterID`, `CharacterName`, `Scopes`.\r\n\r\n## Using tokens with ESI\r\n\r\nPass the access token as a Bearer header:\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer <ACCESS_TOKEN>\" \\\r\n  \"https://esi.evetech.net/latest/characters/<CHARACTER_ID>/wallet/\"\r\n```\r\n\r\n## PKCE (Proof Key for Code Exchange)\r\n\r\nEVE SSO supports PKCE for public clients (no secret key). Generate a `code_verifier` (random 43-128 char string) and derive `code_challenge` via SHA-256:\r\n\r\n```python\r\nimport hashlib, base64, secrets\r\ncode_verifier = secrets.token_urlsafe(64)\r\ncode_challenge = base64.urlsafe_b64encode(\r\n    hashlib.sha256(code_verifier.encode()).digest()\r\n).rstrip(b\"=\").decode()\r\n```\r\n\r\nAdd `&code_challenge=<CHALLENGE>&code_challenge_method=S256` to the authorize URL. Include `code_verifier` in the token exchange.\r\n\r\n## Required Scopes by Category\r\n\r\n| Category | Scope |\r\n|----------|-------|\r\n| Wallet | `esi-wallet.read_character_wallet.v1` |\r\n| Assets | `esi-assets.read_assets.v1` |\r\n| Skills | `esi-skills.read_skills.v1`, `esi-skills.read_skillqueue.v1` |\r\n| Clones | `esi-clones.read_clones.v1`, `esi-clones.read_implants.v1` |\r\n| Location | `esi-location.read_location.v1`, `esi-location.read_ship_type.v1`, `esi"},{"path":"references/endpoints.md","content":"# EVE ESI Character Endpoints Reference\r\n\r\nBase URL: `https://esi.evetech.net/latest`\r\n\r\nAll authenticated endpoints require `Authorization: Bearer <TOKEN>` header. Replace `{character_id}` with the numeric character ID from SSO verify.\r\n\r\n## Table of Contents\r\n\r\n- [Character Info](#character-info)\r\n- [Wallet](#wallet)\r\n- [Assets](#assets)\r\n- [Skills](#skills)\r\n- [Clones and Implants](#clones-and-implants)\r\n- [Location](#location)\r\n- [Contacts](#contacts)\r\n- [Contracts](#contracts)\r\n- [Calendar](#calendar)\r\n- [Fittings](#fittings)\r\n- [Industry](#industry)\r\n- [Killmails](#killmails)\r\n- [Mail](#mail)\r\n- [Market Orders](#market-orders)\r\n- [Mining](#mining)\r\n- [Notifications](#notifications)\r\n- [Loyalty Points](#loyalty-points)\r\n- [Planets (PI)](#planets-pi)\r\n- [Blueprints](#blueprints)\r\n- [Roles and Titles](#roles-and-titles)\r\n- [Standings](#standings)\r\n- [Bookmarks](#bookmarks)\r\n- [Medals](#medals)\r\n- [Agent Research](#agent-research)\r\n- [Fatigue](#fatigue)\r\n- [Faction Warfare](#faction-warfare)\r\n- [Corporation History](#corporation-history)\r\n- [Portrait](#portrait)\r\n- [Search](#search)\r\n- [Fleet](#fleet)\r\n\r\n---\r\n\r\n## Character Info\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/` | -- | Public character info (name, corp, birthday, etc.) |\r\n| GET | `/characters/{character_id}/online/` | `esi-location.read_online.v1` | Online status, last login/logout |\r\n| POST | `/characters/affiliation/` | -- | Bulk lookup corp/alliance/faction for character IDs |\r\n\r\n## Wallet\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/wallet/` | `esi-wallet.read_character_wallet.v1` | ISK balance |\r\n| GET | `/characters/{character_id}/wallet/journal/` | `esi-wallet.read_character_wallet.v1` | Wallet journal (paginated) |\r\n| GET | `/characters/{character_id}/wallet/transactions/` | `esi-wallet.read_character_wallet.v1` | Wallet transactions |\r\n\r\n## Assets\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/assets/` | `esi-assets.read_assets.v1` | All assets (paginated) |\r\n| POST | `/characters/{character_id}/assets/locations/` | `esi-assets.read_assets.v1` | Locations for specific item IDs |\r\n| POST | `/characters/{character_id}/assets/names/` | `esi-assets.read_assets.v1` | Names for specific item IDs |\r\n\r\n## Skills\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{character_id}/skills/` | `esi-skills.read_skills.v1` | All trained skills + total SP |\r\n| GET | `/characters/{character_id}/skillqueue/` | `esi-skills.read_skillqueue.v1` | Current skill queue |\r\n| GET | `/characters/{character_id}/attributes/` | `esi-skills.read_skills.v1` | Character attributes (int, mem, etc.) |\r\n\r\n## Clones and Implants\r\n\r\n| Method | Path | Scope | Description |\r\n|--------|------|-------|-------------|\r\n| GET | `/characters/{"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1815,"uniquenessScore":36,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-04-15T00:45:39.800Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T16:19:20.103Z","emptyReason":null},"items":[{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-10T18:48:31.762Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}