{"id":"89d5014b-4e9e-4ba0-a3e5-bbcfee276713","entityType":"agent","slug":"clawhub-chrischall-workday-fpx","name":"workday-fpx","canonicalUrl":"https://www.xpersona.co/agent/clawhub-chrischall-workday-fpx","canonicalPath":"/agent/clawhub-chrischall-workday-fpx","generatedAt":"2026-10-10T14:47:04.212Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:07:06.332Z","emptyReason":null},"description":"Read Workday HR data (org chart, worker profiles, tasks, pay, benefits, compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use when you want Workday data without the MCP, in a script, or on a machine where the MCP isn't installed.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.4K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:workday-fpx","sourceUrl":"https://clawhub.ai/chrischall/workday-fpx","homepage":"https://clawhub.ai/chrischall/skills/workday-fpx","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/chrischall/workday-fpx","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/chrischall/skills/workday-fpx","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":63,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"workday-fpx technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:07:06.332Z","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-10-10T12:07:06.332Z","emptyReason":null},"stars":null,"forks":null,"downloads":1443,"packageName":null,"latestVersion":"1.1.8","tractionLabel":"1.4K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:07:06.332Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T12:07:06.332Z","lastCrawledAt":"2026-10-10T12:07:06.332Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T12:07:06.332Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.8","createdAt":"2026-10-09T23:28:32.334Z","changelog":"- Removed the sample file skill-card.md. - No changes to functionality or SKILL.md documentation.","fileCount":4,"zipByteSize":8937},{"version":"1.1.7","createdAt":"2026-10-07T13:40:17.314Z","changelog":"- Removed the skill overview file skill-card.md. - No functional or documentation changes to the core skill.","fileCount":4,"zipByteSize":8882},{"version":"1.1.6","createdAt":"2026-10-05T02:52:10.197Z","changelog":"- Removed the file skill-card.md. - No user-facing functionality changes. - Documentation and usage of the skill remain unchanged.","fileCount":4,"zipByteSize":8856},{"version":"1.1.5","createdAt":"2026-10-03T01:45:13.982Z","changelog":"- Removed the file skill-card.md. - No functional or usage changes; documentation and interface remain the same.","fileCount":4,"zipByteSize":8868},{"version":"1.1.4","createdAt":"2026-09-28T14:00:45.979Z","changelog":"- Updated browser extension references from \"Transporter\" to \"ContextMint Bridge\" throughout documentation - Added explicit download and installation guidance for ContextMint Bridge, including Chrome and Safari compatibility notes - Removed outdated references to fetchproxy and Transporter extension - skill-card.md file removed","fileCount":4,"zipByteSize":8857},{"version":"1.1.3","createdAt":"2026-09-25T15:52:05.158Z","changelog":"- Removed the file skill-card.md. - No functional changes to the skill’s core code or documentation.","fileCount":4,"zipByteSize":8629},{"version":"1.1.2","createdAt":"2026-09-23T21:42:42.780Z","changelog":"- Removed the skill-card.md file. - No functional or behavioral changes to the skill; documentation and operation remain the same.","fileCount":4,"zipByteSize":8770},{"version":"1.1.1","createdAt":"2026-09-23T15:41:27.815Z","changelog":"- Removed sample file skill-card.md from the project. - No functional changes to the skill itself. This is a maintenance release focused on cleaning up documentation files.","fileCount":4,"zipByteSize":8789}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:workday-fpx","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:workday-fpx` 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/chrischall/workday-fpx 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-chrischall-workday-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/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-10T14:47:04.209Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-workday-fpx/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-10-10T12:07:06.332Z","emptyReason":null},"readme":"Skill: workday-fpx\n\nOwner: chrischall\n\nSummary: Read Workday HR data (org chart, worker profiles, tasks, pay, benefits, compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use when you want Workday data without the MCP, in a script, or on a machine where the MCP isn't installed.\n\nTags: latest:1.1.8\n\nVersion history:\n\nv1.1.8 | 2026-10-09T23:28:32.334Z | auto\n\n- Removed the sample file skill-card.md.\n- No changes to functionality or SKILL.md documentation.\n\nv1.1.7 | 2026-10-07T13:40:17.314Z | auto\n\n- Removed the skill overview file skill-card.md.\n- No functional or documentation changes to the core skill.\n\nv1.1.6 | 2026-10-05T02:52:10.197Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing functionality changes.\n- Documentation and usage of the skill remain unchanged.\n\nv1.1.5 | 2026-10-03T01:45:13.982Z | auto\n\n- Removed the file skill-card.md.\n- No functional or usage changes; documentation and interface remain the same.\n\nv1.1.4 | 2026-09-28T14:00:45.979Z | auto\n\n- Updated browser extension references from \"Transporter\" to \"ContextMint Bridge\" throughout documentation\n- Added explicit download and installation guidance for ContextMint Bridge, including Chrome and Safari compatibility notes\n- Removed outdated references to fetchproxy and Transporter extension\n- skill-card.md file removed\n\nv1.1.3 | 2026-09-25T15:52:05.158Z | auto\n\n- Removed the file skill-card.md.\n- No functional changes to the skill’s core code or documentation.\n\nv1.1.2 | 2026-09-23T21:42:42.780Z | auto\n\n- Removed the skill-card.md file.\n- No functional or behavioral changes to the skill; documentation and operation remain the same.\n\nv1.1.1 | 2026-09-23T15:41:27.815Z | auto\n\n- Removed sample file skill-card.md from the project.\n- No functional changes to the skill itself. This is a maintenance release focused on cleaning up documentation files.\n\nv1.1.0 | 2026-09-20T02:49:58.777Z | auto\n\n- Removed the sample skill-card.md file.\n- No functional or interface changes; documentation and usage remain the same.\n\nv1.0.0 | 2026-09-18T15:10:59.143Z | auto\n\n- Initial release of workday-fpx skill.\n- Enables reading Workday HR data (org chart, profiles, tasks, pay, benefits, compensation, app menu) from the command line using the fpx CLI.\n- No need to run the workday-mcp server; works via your signed-in *.myworkday.com browser tab using the Transporter extension.\n- Supports fetching any *.htmld data endpoint with raw JSON output, ready for jq processing.\n- Removed sample skill-card.md file.\n\nv0.6.5 | 2026-09-15T19:24:34.239Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing features or documentation were changed.\n\nv0.6.4 | 2026-09-14T14:08:44.255Z | auto\n\n- Removed the skill-card.md file.\n- No impact on functionality or usage; documentation file cleanup only.\n\nv0.6.3 | 2026-09-10T17:52:13.714Z | auto\n\n- Removed the sample file skill-card.md.\n- No functional or documentation changes to code or main documentation.\n\nv0.6.2 | 2026-09-09T21:16:37.492Z | auto\n\n- Removed the sample file skill-card.md.\n- No functional or user-facing changes were made in this version.\n\nv0.6.1 | 2026-09-05T00:51:16.529Z | auto\n\n- Removed the file sample/skill-card.md.\n- No changes to core functionality or documentation content.\n\nv0.6.0 | 2026-09-04T22:22:36.170Z | auto\n\n- Removed the unused skill-card.md file.\n- No changes to functionality or setup instructions.\n\nv0.5.0 | 2026-08-29T13:54:30.017Z | auto\n\n- Removed the skill card file (skill-card.md).\n- No feature or documentation changes; core functionality and usage instructions remain unchanged.\n\nv0.4.1 | 2026-08-28T21:07:36.647Z | auto\n\n- Removed the redundant skill-card.md file.\n- No functional or user-facing changes.\n\nv0.4.0 | 2026-08-19T04:08:48.061Z | auto\n\n**Expanded endpoint support and documentation improvements.**\n\n- Added support and documentation for fetching org chart and detailed worker profiles (with drill-in tasks).\n- Updated references/endpoints.md with new verified GET endpoints and clear notes on unsupported features.\n- Clarified documentation on coverage/exclusions: notes now specify that inbox and global search are only available via GraphQL (POST), not GET.\n- Removed outdated skill-card.md file.\n\nv0.3.2 | 2026-08-06T00:43:19.009Z | auto\n\n- Removed the redundant skill-card.md file.\n- No functional changes to logic or usage; documentation and core workflow unchanged.\n- Skill remains focused on fetching Workday HR data via the fpx CLI using a browser-authenticated session.\n\nv0.3.1 | 2026-07-30T12:53:42.097Z | auto\n\nworkday-fpx 0.3.1\n\n- Added detailed usage and setup instructions in SKILL.md.\n- Documented key path rules, endpoint access patterns, and jq projection requirements.\n- Clarified session handling, SSO caveats, and troubleshooting for non-JSON responses.\n- Outlined exit codes and core operational limitations.\n- Provided examples and references for safe Workday data access via the fpx CLI without needing the MCP server.\n\nArchive index:\n\nArchive v1.1.8: 4 files, 8937 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (2180b), SKILL.md (6305b), _meta.json (130b)\n\nFile v1.1.8:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the ContextMint Bridge extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the\nchrome zip unpacked, after checking it against the `.sha256` beside it; Safari is\nnot available yet (it will ship inside the ContextMint app, which has no public\ndownload link), so use Chrome for now — it is the fetchproxy browser extension\nrenamed, source public at https://github.com/nullnet-app/contextmint-bridge), an\nopen tab at `https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.8:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1791588512334\n}\n\nFile v1.1.8:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.8:skill-card.md\n\n## Description:\n\nGuides employees in reading Workday HR data through their signed-in browser session using the fpx CLI, without a separate MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nAuthorized employees and developers use this skill to retrieve Workday org charts, worker profiles, tasks, pay, benefits, compensation, and app listings through their existing signed-in session.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Access through a signed-in browser session can expose confidential HR, pay, benefits, compensation, and worker-profile data.\n\nMitigation: Use only with organizational authorization, treat results as confidential, and redact personal and compensation fields by default.\n\nRisk: Raw Workday responses may expose a session security token and sensitive employee data.\n\nMitigation: Project only required fields, avoid raw response logging, and never print the session security token.\n\nRisk: A paired browser bridge may retain access to the signed-in Workday session.\n\nMitigation: Restrict extension site access and remove or unpair the bridge when it is no longer needed.\n\n## Reference(s):\n\n- [ClawHub skill listing](https://clawhub.ai/chrischall/skills/workday-fpx)\n- [Workday endpoint reference](references/endpoints.md)\n- [ContextMint Bridge source](https://github.com/nullnet-app/contextmint-bridge)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell and jq examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only examples project selected fields from JSON responses.]\n\n## Skill Version(s):\n\n1.1.8 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.7: 4 files, 8882 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (1936b), SKILL.md (6305b), _meta.json (130b)\n\nFile v1.1.7:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the ContextMint Bridge extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the\nchrome zip unpacked, after checking it against the `.sha256` beside it; Safari is\nnot available yet (it will ship inside the ContextMint app, which has no public\ndownload link), so use Chrome for now — it is the fetchproxy browser extension\nrenamed, source public at https://github.com/nullnet-app/contextmint-bridge), an\nopen tab at `https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.7:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.7\",\n  \"publishedAt\": 1791380417314\n}\n\nFile v1.1.7:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.7:skill-card.md\n\n## Description:\n\nGuides authorized Workday users in reading HR data through their signed-in browser session with fpx, without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nAuthorized employees and administrators use this skill to retrieve their permitted Workday org, profile, pay, benefits, and task data from a shell without an MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Workday responses may expose confidential HR information.\n\nMitigation: Access only authorized tenant data, project only needed fields, and avoid logging raw responses.\n\nRisk: Raw response envelopes can include a session secret.\n\nMitigation: Use the field-selecting filters rather than printing the full response.\n\nRisk: The CLI and paired browser extension require access to the signed-in Workday session.\n\nMitigation: Review the CLI installation, extension, pairing, and site-access permissions before use.\n\n## Reference(s):\n\n- [Workday FPX on ClawHub](https://clawhub.ai/chrischall/skills/workday-fpx)\n- [Workday endpoint and filtering guide](artifact/references/endpoints.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Text and Markdown with shell examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only guidance; responses can contain confidential HR data.]\n\n## Skill Version(s):\n\n1.1.7 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.6: 4 files, 8856 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (1886b), SKILL.md (6305b), _meta.json (130b)\n\nFile v1.1.6:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the ContextMint Bridge extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the\nchrome zip unpacked, after checking it against the `.sha256` beside it; Safari is\nnot available yet (it will ship inside the ContextMint app, which has no public\ndownload link), so use Chrome for now — it is the fetchproxy browser extension\nrenamed, source public at https://github.com/nullnet-app/contextmint-bridge), an\nopen tab at `https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.6:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.6\",\n  \"publishedAt\": 1791168730197\n}\n\nFile v1.1.6:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.6:skill-card.md\n\n## Description:\n\nHelps employees read their Workday HR data through an already signed-in browser session using the fpx CLI, without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nEmployees use the skill to retrieve their own Workday app menu, worker profiles, org chart, tasks, pay, benefits, and compensation from a signed-in session for review or scripting.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Access routes a signed-in Workday session through the browser bridge.\n\nMitigation: Install only if comfortable using the bridge with your own signed-in session; follow your organization's HR data handling rules.\n\nRisk: Workday results may expose sensitive HR data or session details when shared or logged.\n\nMitigation: Query only needed fields, avoid raw response dumps and shared logs, and redact results before sharing.\n\n## Reference(s):\n\n- [Workday via fpx on ClawHub](https://clawhub.ai/chrischall/skills/workday-fpx)\n- [Workday endpoint and field-selection guide](references/endpoints.md)\n- [ContextMint Bridge extension](https://github.com/nullnet-app/contextmint-bridge)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance, JSON]\n\n**Output Format:** [Markdown instructions with shell commands and field-selected JSON responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Results may contain sensitive HR information.]\n\n## Skill Version(s):\n\n1.1.6 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.5: 4 files, 8868 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (1828b), SKILL.md (6305b), _meta.json (130b)\n\nFile v1.1.5:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the ContextMint Bridge extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the\nchrome zip unpacked, after checking it against the `.sha256` beside it; Safari is\nnot available yet (it will ship inside the ContextMint app, which has no public\ndownload link), so use Chrome for now — it is the fetchproxy browser extension\nrenamed, source public at https://github.com/nullnet-app/contextmint-bridge), an\nopen tab at `https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.5:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.5\",\n  \"publishedAt\": 1790991913982\n}\n\nFile v1.1.5:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.5:skill-card.md\n\n## Description:\n\nGuides employees in reading Workday HR data through their signed-in browser session using the fpx CLI, without running an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nEmployees use this skill to retrieve their accessible Workday profiles, organization details, tasks, pay, and benefits from a signed-in browser session for shell-based workflows.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Sensitive HR information may pass through persistent third-party browser and CLI tooling.\n\nMitigation: Use only if organizational policy permits this access method, on a managed private machine; revoke extension pairing when finished.\n\nRisk: Raw responses may expose confidential HR records or session tokens in terminal output and logs.\n\nMitigation: Request only necessary fields, project results before display, and avoid raw dumps and terminal or file logging.\n\n## Reference(s):\n\n- [Workday endpoint recipes](references/endpoints.md)\n- [ContextMint Bridge extension releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell commands and jq filters]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Field-selected results; avoid exposing raw Workday response envelopes.]\n\n## Skill Version(s):\n\n1.1.5 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.4: 4 files, 8857 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (1879b), SKILL.md (6305b), _meta.json (130b)\n\nFile v1.1.4:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the ContextMint Bridge extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the\nchrome zip unpacked, after checking it against the `.sha256` beside it; Safari is\nnot available yet (it will ship inside the ContextMint app, which has no public\ndownload link), so use Chrome for now — it is the fetchproxy browser extension\nrenamed, source public at https://github.com/nullnet-app/contextmint-bridge), an\nopen tab at `https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.4:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.4\",\n  \"publishedAt\": 1790604045979\n}\n\nFile v1.1.4:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.4:skill-card.md\n\n## Description:\n\nGuides agents in reading Workday HR data through a user's signed-in browser session using the fpx CLI instead of an MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nEmployees and developers use this skill to read Workday app menus, worker profiles, org charts, tasks, pay, and benefits from an existing signed-in browser session without running an MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The fpx CLI and ContextMint Bridge can access Workday pages available to the signed-in browser session.\n\nMitigation: Install and pair them only if you are comfortable granting that access.\n\nRisk: Raw Workday responses may expose session tokens or sensitive HR information.\n\nMitigation: Use the supplied field-selecting jq projections; do not print or store raw responses.\n\n## Reference(s):\n\n- [Workday FPX skill listing](https://clawhub.ai/chrischall/skills/workday-fpx)\n- [Workday endpoint and jq recipes](references/endpoints.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Configuration instructions, Guidance]\n\n**Output Format:** [Markdown with shell and jq examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Field-selected Workday data; raw responses may contain sensitive HR information or session tokens.]\n\n## Skill Version(s):\n\n1.1.4 (source: server-resolved release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.3: 4 files, 8629 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (1822b), SKILL.md (5878b), _meta.json (130b)\n\nFile v1.1.3:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the Transporter extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** extension installed, an open tab at\n`https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.3:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.3\",\n  \"publishedAt\": 1790351525158\n}\n\nFile v1.1.3:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.3:skill-card.md\n\n## Description:\n\nGuides employees in reading Workday HR information through their signed-in browser session using the fpx CLI instead of a separate MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nEmployees and authorized developers use the skill to look up specific Workday app, worker, org chart, pay, or benefits information from an existing signed-in session without running the Workday MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: An authenticated Workday session may expose sensitive HR information about other employees.\n\nMitigation: Limit use to specific authorized lookups; avoid bulk crawling and handle results under employer HR-data policies.\n\nRisk: Raw Workday responses can expose sensitive data or session information.\n\nMitigation: Never print or save raw responses; project only the fields needed for the lookup.\n\n## Reference(s):\n\n- [Workday endpoint recipes](references/endpoints.md)\n- [ClawHub workday-fpx release](https://clawhub.ai/chrischall/skills/workday-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance, Configuration instructions]\n\n**Output Format:** [Markdown with shell commands and jq filters]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Responses may contain sensitive HR data; show only fields needed for the authorized lookup.]\n\n## Skill Version(s):\n\n1.1.3 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.2: 4 files, 8770 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (2200b), SKILL.md (5878b), _meta.json (130b)\n\nFile v1.1.2:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the Transporter extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** extension installed, an open tab at\n`https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1790199762780\n}\n\nFile v1.1.2:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.2:skill-card.md\n\n## Description:\n\nRead Workday HR data, including org chart, worker profiles, tasks, pay, benefits, compensation, and app menu data, from a shell with the fpx CLI through the user's already signed-in myworkday.com browser session.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, engineers, and Workday users use this skill to fetch their own Workday data from a shell when they need scriptable access without running the Workday MCP server. It provides setup steps, endpoint patterns, jq projections, and troubleshooting guidance for read-only Workday htmld data requests.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill uses fpx and the Transporter extension to make Workday requests through the user's active signed-in browser session.\n\nMitigation: Install and pair it only when that access model is acceptable, and keep requests scoped to the user's own authorized Workday data.\n\nRisk: Raw Workday response envelopes may include session tokens and sensitive HR data.\n\nMitigation: Use the field-selecting jq filters provided by the skill instead of dumping raw responses.\n\n## Reference(s):\n\n- [Workday htmld endpoints for fpx](references/endpoints.md)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/workday-fpx)\n- [Publisher profile](https://clawhub.ai/user/chrischall)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Code, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with shell commands, endpoint patterns, and jq filters]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Outputs are intended to be reviewed and adapted for the user's own Workday host, tenant, signed-in browser session, and selected fields.]\n\n## Skill Version(s):\n\n1.1.2 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.1: 4 files, 8789 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (2143b), SKILL.md (5878b), _meta.json (130b)\n\nFile v1.1.1:SKILL.md\n\n---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the Transporter extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** extension installed, an open tab at\n`https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA routes are HTML, not data.** `/{tenant}/d/...` returns the app\n  shell — never fetch it. If you copied a `/{tenant}/d/inst/....htmld` URL\n  from your browser, drop the `/d/` segment to get the data endpoint:\n  `/{tenant}/inst/....htmld`.\n- **A bare task id resolves directly**: an id shaped like `2998$43525`\n  (digits `$` alnum/`-`/`_`) is the constructable endpoint\n  `/{tenant}/task/2998$43525.htmld` — no page-context token needed. Container\n  / launcher task ids often return a near-empty shell; rich data needs the\n  `cacheable-task` → `card/all` crawl below.\n- **Data-card paths carry an opaque, page-context-bound token** (the\n  `<pageCtx>` segment in `/{tenant}/card/all/<cardId>/<pageCtx>.htmld`) —\n  it is NOT constructable. Get it from the parent `cacheable-task` response's\n  own references, or by pasting the URL of the page you have open.\n- A trailing `#fragment` on a copied URL is inert — strip it before fetching.\n\n## Resolve-first rule\n\nCall the apps list first (`quickaccess/fetch.htmld`, above) to discover a\n`taskId`, or open the target page in your browser and copy its URL — then\nfetch that specific task/card path. There's no search/id-lookup step here;\nWorkday's own navigation supplies the ids.\n\n## Never dump the raw envelope — project fields only\n\nEvery `*.htmld` response's `root` envelope carries a **`sessionSecureToken`**\n(and other envelope-internal fields) alongside the real data in `body`. The\n`workday-mcp` parser (`src/parse.ts`) never emits it — it reads an explicit\nallowlist only. Do the same here: **never pipe a response through bare\n`jq '.'`** — always use one of the field-selecting filters in\n`references/endpoints.md` (they select `text`/`moniker`/`configuredAppsItem`\nwidget nodes, never the envelope wholesale), so nothing secret rides into\nyour terminal or a script's output.\n\n## Session-expiry tell\n\nA stale SSO session bounces the fetch to the IdP instead of returning JSON.\nSigns (`fpx` still exits `0` — Workday returns this as a 200):\n- The response isn't JSON — it's an HTML login/SAML page (grep for\n  `SAMLRequest`, `pingfederate`, or `Sign On to`).\n- `fpx`'s reported final URL host differs from the tenant host (cross-origin\n  redirect to the IdP).\n\nFix: open `https://<host>/<tenant>` in your browser, complete SSO, and\nretry — there's no separate login step for `fpx`.\n\n## Exit codes (fetch verbs)\n\n- `0` — success (still check the body isn't an SSO/login page — see above).\n- `2` — bridge unavailable: extension not connected or pairing pending →\n  `fpx pair -p workday`, confirm a `myworkday.com` tab is open.\n- `3` — bot wall (not expected on an internal SSO tenant, but the generic\n  fpx contract).\n- `4` — upstream non-2xx from Workday.\n\n## Notes\n\n- Read-only, and touches only your own data — this is the same surface the\n  `workday_*` MCP tools read, not the official admin-only REST/SOAP API.\n- `fpx health -p workday` shows bridge connection state when a call fails.\n- Inbox/\"My Tasks\" and global search have no GET-able endpoint — they are served\n  by the GraphQL surface (`/wday/pex/graphql/graphql?operation=...`, POST). See\n  `references/endpoints.md` for what else was verified NOT GET-able, so you\n  don't re-probe it.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1790178087815\n}\n\nFile v1.1.1:references/endpoints.md\n\n# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Project the hub response the same way as\nendpoint 2; the child card usually contains list-card rows (see below).\n\n## 4. List-card rows (e.g. a benefits cost table)\n\nA list/table section's `contentSectionItems[]` are ROW objects keyed by\nclean column names (`label`, `value`, `secondaryValue`, `task`,\n`onInstance`, …) rather than a flat `text` widget — key on the **column\nname**, not `propertyName` (Workday's real propertyNames are namespaced,\n`wd:Label`/`nyw:Value`, and are template noise here). Approximate the\nrow read with:\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  .body.cardContentSections[]? | {\n    section: .contentSectionName,\n    rows: [.contentSectionItems[]? | {\n      label: (.label.value // .label.label // empty),\n      value: ([.value.value, .secondaryValue.value] | map(select(. != null)) | join(\" \")),\n    }]\n  }'\n```\n\nDrill-in references for a row come from its navigational columns only\n(`task`, `onInstance`, `relatedTaskInstance`, `quicklinkItem` — `uxIcon`/\n`image` monikerLists are decoration):\n\n```sh\nfpx get \"https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld\" -p workday | jq '\n  [.body.cardContentSections[]?.contentSectionItems[]?\n   | (.task, .onInstance, .relatedTaskInstance, .quicklinkItem)?\n   | select(. != null)\n   | .. | objects | select(.widget==\"moniker\") | {text, instanceId}]'\n```\n\n## 5. Worker profile → the drill-in catalog (the manager surface)\n\n```\nGET https://$HOST/$TENANT/inst/<workerCtx>/<workerIid>.htmld\n```\n\nReturns \"View Associate\": a `compositeView` listing ~40 named, fetchable tasks\nacross 9 sections. `<workerCtx>` differs per tenant — read it off an org-chart\nnode's concrete profile uri (endpoint 6) rather than guessing.\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/1\\$715/247\\$42.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"compositeViewSection\")\n   | {section: .label,\n      tasks: [.taskNodes | .. | objects | select(.widget==\"compositeViewTask\")\n              | {label, uri: (.uri + \".htmld\")}]}]'\n```\n\nThen fetch any of those uris (**`.htmld` must be appended — the bare form 404s**):\n\n```\nGET https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\n```\n\n## 6. Org chart (the reporting chain)\n\n```\nGET https://$HOST/$TENANT/task/<orgChartTaskId>.htmld\n```\n\nGet `<orgChartTaskId>` from endpoint 1 (the app labelled \"Org Chart\").\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$2673.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"hierarchyNavigator\")\n   | {workerIid,\n      chain: [.ancestors[]? | {\n        name:  (.navigatorInstance.instances[0].text // null),\n        profileUri: (.navigatorInstance.selfUriTemplate + \".htmld\"),\n        title: (.navigatorItems[0].detailOne // null),\n        location: (.navigatorItems[0].detailTwo // null),\n        reports: (.navigatorItems[0].detailThree // null)}]}]'\n```\n\n`selfUriTemplate` is already CONCRETE here (one uri per person) — this is where\nthe `<workerCtx>` for endpoint 5 comes from. Note the chain runs UPWARD only;\nexpanding DOWN to direct reports is a POST-only navigation and 404s on GET.\n\n## 7. Grids (real tables)\n\nMany pages return a `grid` rather than card sections. Cells are keyed by an\nopaque `columnId`, so join to `columns[]`:\n\n```sh\nfpx get \"https://$HOST/$TENANT/inst/<ctx>/rel-task/<taskId>.htmld\" -p workday | jq '\n  [.. | objects | select(.widget==\"grid\") | . as $g\n   | ($g.columns | map({key: .columnId, value: .label}) | from_entries) as $cols\n   | {label: $g.label, rows: $g.rowCount, total: $g.deepRowCount,\n      chunkingUrl: $g.chunkingUrl,\n      data: [$g.rows[]? | .cellsMap | with_entries(\n               .key |= ($cols[.] // .)\n             ) | map_values(.value // .instances[0].text // null)]}]'\n```\n\n**`deepRowCount > rowCount` means the grid is CHUNKED** — you have only the\nfirst page, and `chunkingUrl` serves the rest. Don't report it as complete.\n\n## 8. Healthcheck probe (tiny authenticated endpoint)\n\n```\nGET https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/get-global-prefs.htmld?feature=doNotShowMobileAd\" -p workday | jq -r '\n  if (type==\"object\") then \"ok (\\(. | length) top-level keys)\" else \"unexpected body\" end'\n```\n\nCheap way to confirm the bridge + tab + SSO session are all alive before a\nbigger crawl — a non-JSON/HTML result here means the session expired (see\nSKILL.md's session-expiry tell).\n\n---\n\n## SPA URL → data endpoint\n\nIf you copy a URL from your open Workday tab and it contains `/d/`\n(`https://$HOST/$TENANT/d/inst/....htmld`), drop the `/d/` segment before\nfetching — that path is the HTML app shell, not data:\n\n```sh\nurl=\"https://wd5.myworkday.com/acme/d/inst/13102!ABC/cacheable-task/2998\\$43525.htmld\"\ndata_url=\"${url/\\/d\\///}\"   # → .../acme/inst/13102!ABC/cacheable-task/2998$43525.htmld\nfpx get \"$data_url\" -p workday | jq '...'\n```\n\n## Gotchas that cost real debugging time\n\n- **Most uris arrive WITHOUT `.htmld` and 404 until you append it** — `inst`,\n  `rel-task` and `task` paths alike.\n- **`moniker.target` is the best navigation edge**: a URL-ENCODED ABSOLUTE url.\n  Decode it and drop the `/d/` segment, then it fetches.\n  `jq -r '.target | @uri \"\\(.)\"'` won't do it — use\n  `python3 -c 'import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))'`.\n- **Uri templates come in three dialects**: `{id}`, `[IID]`, and\n  already-concrete. Substituting only `{id}` yields unfetchable uris.\n- **A page with no `cardContentSections` is not empty** — it is probably a grid,\n  a compositeView, a hierarchyNavigator, a landingPage, or a report PROMPT form\n  (`monikerListInput` / `textInput` widgets, which need a POST of parameters).\n\n## Verified NOT GET-able (don't burn time here)\n\n- `/{tenant}/navigable/<iid>` and `/navigable/bundler` — org-chart expansion to\n  direct reports. POST-only.\n- `/{tenant}/worklet/<workletIid>`, `/{tenant}/print/navigable/...` — 404.\n- `/{tenant}/search.htmld` — returns an empty `federatedSearchResults` shell;\n  `q`, `st`, `searchText`, `query`, `text`, `keyword` and `s` were all tried and\n  none is the query parameter.\n- **GraphQL surface** (`/wday/pex/graphql/graphql?operation=...`, POST) — serves\n  the inbox/\"My Tasks\" and search. Reachable, but no operation shape is captured\n  in the repo, so it's left out here rather than guessed.\n- **Writes** — none exist in workday-mcp (read-only); Workday writes are\n  multi-step business processes, not single POSTs.\n\nFile v1.1.1:skill-card.md\n\n## Description:\n\nRead Workday HR data such as org charts, worker profiles, tasks, pay, benefits, compensation, and app-menu data from a shell with the fpx CLI through the user's own signed-in Workday browser session.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nEmployees, developers, and operators with authorized Workday access use this skill to retrieve read-only Workday data from tenant-scoped endpoints for inspection, scripting, and troubleshooting without running the Workday MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can access sensitive HR and PII through an already signed-in Workday browser session.\n\nMitigation: Install and use it only with organizational authorization, treat all output as sensitive, and avoid storing or sharing results casua\n\nArchive v1.1.0: 4 files, 8923 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (2399b), SKILL.md (5878b), _meta.json (130b)\n\nArchive v1.0.0: 4 files, 8888 bytes\n\nFiles: references/endpoints.md (9502b), skill-card.md (2356b), SKILL.md (5878b), _meta.json (130b)","readmeExcerpt":"Skill: workday-fpx Owner: chrischall Summary: Read Workday HR data (org chart, worker profiles, tasks, pay, benefits, compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use when you want Workday data without the MCP, in a script, or","codeSnippets":[],"executableExamples":[{"language":"sh","snippet":"npm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in ContextMint Bridge"},{"language":"sh","snippet":"fpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'"},{"language":"text","snippet":"GET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true"},{"language":"sh","snippet":"fpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'"},{"language":"text","snippet":"GET https://$HOST/$TENANT/task/<taskId>.htmld"},{"language":"sh","snippet":"fpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: workday-fpx\ndescription: >-\n  Read Workday HR data (org chart, worker profiles, tasks, pay, benefits,\n  compensation, your app menu) from a shell with the fpx CLI (@fetchproxy/cli)\n  instead of running the workday-mcp server — fetch any *.htmld data endpoint through your own\n  signed-in *.myworkday.com tab (SSO/Ping/Okta/Entra already cleared). Use\n  when you want Workday data without the MCP, in a script, or on a machine\n  where the MCP isn't installed.\n---\n\n# Workday via fpx (no MCP)\n\nWorkday employees have no personal API — the official REST/SOAP surface\nneeds a tenant-admin-registered OAuth client. The only usable surface is the\nemployee's own signed-in web session behind corporate SSO (Ping/Okta/Entra +\nMFA). `fpx` routes the request through the user's already-authenticated\n`*.myworkday.com` browser tab (the ContextMint Bridge extension), so a `*.htmld`\ndata endpoint that would otherwise bounce to the IdP returns clean JSON.\n\nThis is the same access the `workday_*` MCP tools use (a widget-tree JSON\nresponse, parsed here with `jq` instead of `workday-mcp`'s TypeScript\nparser), reached with one CLI call instead of a running server.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli                # provides `fpx`\nfpx profile add workday --domain myworkday.com # apex domain (per-tenant subdomain e.g. wd5)\nfpx pair -p workday                            # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** extension installed (from\nhttps://github.com/nullnet-app/contextmint-bridge/releases — Chrome: load the\nchrome zip unpacked, after checking it against the `.sha256` beside it; Safari is\nnot available yet (it will ship inside the ContextMint app, which has no public\ndownload link), so use Chrome for now — it is the fetchproxy browser extension\nrenamed, source public at https://github.com/nullnet-app/contextmint-bridge), an\nopen tab at `https://<host>/<tenant>` (e.g. `https://wd5.myworkday.com/acme`) with SSO\nalready completed, and the extension's Chrome **Site access** allowing\n`myworkday.com`. Pairing persists — after the first approval every later\n`fpx` call reuses it.\n\n## Core call\n\nEvery read is a `GET` of a tenant-scoped `*.htmld` data endpoint. Send it raw\nso stdout is the JSON body, ready for `jq`:\n\n```sh\nfpx get 'https://wd5.myworkday.com/acme/quickaccess/fetch.htmld?shouldFetchUpcApps=true' -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nReady-to-run endpoint paths (apps list, task/data-card read, worker profile +\nits ~40-task drill-in catalog, org chart, grid tables, healthcheck probe) with\n`jq` projection recipes are in `references/endpoints.md`. The\nfull widget-tree schema and gotchas are captured in the repo at\n`docs/WORKDAY-API.md` — the operations here are the same live-verified\nshapes `src/client.ts` / `src/tools/*.ts` use.\n\n## Path rules (mirror `WorkdayClient.resolvePath`)\n\n- **SPA route"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"workday-fpx\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1791588512334\n}"},{"path":"references/endpoints.md","content":"# Workday `*.htmld` endpoints for fpx\n\nReady-to-run paths for `fpx get '<url>' -p workday`. All shapes are\nlive-verified in the repo (`src/client.ts`, `src/tools/*.ts`,\n`docs/WORKDAY-API.md`) against a production tenant on `wd5.myworkday.com`\n(cards 2026-06, the manager surfaces 2026-08). Replace\n`wd5.myworkday.com`/`acme` with your own `$HOST`/`$TENANT`.\n\nEvery response is a `root` envelope: page chrome (`title`, `taskId`,\n`tenant`, `currentUser`, `accountTasks`, `header` export links,\n**`sessionSecureToken` — SECRET, never project this**) plus a `body`.\n**`body` is NOT always `cardContentSections`** — Workday serves seven page\nfamilies (data card, `grid`, form/`fieldSet`, `compositeView` worker profile,\n`hierarchyNavigator` org chart, `landingPage` hub, and report prompt forms),\nso a page that looks empty under a `cardContentSections` filter usually is\nnot. **Always pipe through one of the filters below — never bare `jq '.'`.**\n\n---\n\n## 1. List your apps (the discovery entry point)\n\n```\nGET https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\n```\n\n```sh\nfpx get \"https://$HOST/$TENANT/quickaccess/fetch.htmld?shouldFetchUpcApps=true\" -p workday \\\n  | jq '[.. | objects | select(.widget==\"configuredAppsItem\") | {label, taskId: .taskIid}] | unique_by(.label)'\n```\n\nA `widget/children` tree; leaf `configuredAppsItem` nodes carry `label` +\n`taskIid`. Some apps share a generic launcher id (e.g. `2997$2151`) and open\nto a near-empty page — for those, open the app in your browser and use its\npage URL with endpoint 3 instead.\n\n## 2. Task by id (constructable — no page-context token needed)\n\n```\nGET https://$HOST/$TENANT/task/<taskId>.htmld\n```\n\n`<taskId>` looks like `2998$43525` (from endpoint 1, or a prior response's\nreferences). Returns clean JSON for any task id, but **container/launcher\ntasks return a near-empty shell** (no `cardContentSections`) — rich data\nneeds endpoints 3+4 below.\n\n```sh\nfpx get \"https://$HOST/$TENANT/task/2998\\$43525.htmld\" -p workday | jq '{\n  title: (if (.title|type)==\"object\" then .title.text else .title end),\n  fields: [.. | objects | select(.widget==\"text\") | {label, value}],\n  refs:   [.. | objects | select(.widget==\"moniker\") | {text, instanceId}],\n  relatedTasks: (.accountTasks // [])\n}'\n```\n\n(Escape the literal `$` in a task id before the shell expands it, as shown.)\n\n## 3. Task hub → data card crawl (rich data)\n\nContainer tasks (Benefits and Pay, etc.) delegate to child cards through two\nopaque, page-context-bound tokens you can only get by loading the parent:\n\n```\nGET https://$HOST/$TENANT/inst/<pageCtx>/cacheable-task/<taskId>.htmld   # the hub\nGET https://$HOST/$TENANT/card/all/<cardId>/<pageCtx>.htmld              # a child card (the real content)\n```\n\n`<pageCtx>` is NOT constructable — read it off the hub response's own\nreferences/uris (or copy the child card's URL from your open browser tab).\nThe `cacheable-task` token is comparatively stable across loads; the\n`card/all` child token rotates. Projec"},{"path":"skill-card.md","content":"## Description:\n\nGuides employees in reading Workday HR data through their signed-in browser session using the fpx CLI, without a separate MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nAuthorized employees and developers use this skill to retrieve Workday org charts, worker profiles, tasks, pay, benefits, compensation, and app listings through their existing signed-in session.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Access through a signed-in browser session can expose confidential HR, pay, benefits, compensation, and worker-profile data.\n\nMitigation: Use only with organizational authorization, treat results as confidential, and redact personal and compensation fields by default.\n\nRisk: Raw Workday responses may expose a session security token and sensitive employee data.\n\nMitigation: Project only required fields, avoid raw response logging, and never print the session security token.\n\nRisk: A paired browser bridge may retain access to the signed-in Workday session.\n\nMitigation: Restrict extension site access and remove or unpair the bridge when it is no longer needed.\n\n## Reference(s):\n\n- [ClawHub skill listing](https://clawhub.ai/chrischall/skills/workday-fpx)\n- [Workday endpoint reference](references/endpoints.md)\n- [ContextMint Bridge source](https://github.com/nullnet-app/contextmint-bridge)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell and jq examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only examples project selected fields from JSON responses.]\n\n## Skill Version(s):\n\n1.1.8 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1565,"uniquenessScore":43,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T12:07:06.332Z","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-10-10T12:07:06.332Z","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-10T14:47:04.212Z","emptyReason":null},"items":[{"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-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"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":"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"}]}}}