{"id":"161b3deb-1961-4a83-9a07-0e93b71fb305","entityType":"agent","slug":"clawhub-chrischall-hemnet-fpx","name":"hemnet-fpx","canonicalUrl":"https://www.xpersona.co/agent/clawhub-chrischall-hemnet-fpx","canonicalPath":"/agent/clawhub-chrischall-hemnet-fpx","generatedAt":"2026-10-10T11:52:49.012Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:43:13.291Z","emptyReason":null},"description":"Query hemnet.se (Swedish property portal) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve locations, search for-sale and sold listings, and read listing detail via one-shot GraphQL calls through a signed-in browser tab. Use when you want Hemnet 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.5K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:hemnet-fpx","sourceUrl":"https://clawhub.ai/chrischall/hemnet-fpx","homepage":"https://clawhub.ai/chrischall/skills/hemnet-fpx","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/chrischall/hemnet-fpx","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/chrischall/skills/hemnet-fpx","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":64,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"hemnet-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-10T09:43:13.291Z","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-10T09:43:13.291Z","emptyReason":null},"stars":null,"forks":null,"downloads":1518,"packageName":null,"latestVersion":"1.1.11","tractionLabel":"1.5K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T09:43:13.290Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T09:43:13.291Z","lastCrawledAt":"2026-10-10T09:43:13.290Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T09:43:13.290Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.11","createdAt":"2026-10-09T23:26:26.737Z","changelog":"- Removed the file skill-card.md. - No user-facing changes; documentation and usage remain the same.","fileCount":4,"zipByteSize":5812},{"version":"1.1.10","createdAt":"2026-10-07T13:35:14.784Z","changelog":"- Removed the skill-card.md file. - No changes to functionality or documentation except for this file removal.","fileCount":4,"zipByteSize":5751},{"version":"1.1.9","createdAt":"2026-10-05T02:50:47.696Z","changelog":"- Removed the file skill-card.md. - No changes to functionality or documentation content.","fileCount":4,"zipByteSize":5692},{"version":"1.1.8","createdAt":"2026-10-03T01:41:36.008Z","changelog":"- Removed the file: skill-card.md. - No other functional or user-facing changes.","fileCount":4,"zipByteSize":5704},{"version":"1.1.7","createdAt":"2026-10-01T18:25:08.370Z","changelog":"- Removed the skill-card.md file. - No changes to functionality or documentation content.","fileCount":4,"zipByteSize":5722},{"version":"1.1.6","createdAt":"2026-09-28T13:55:23.329Z","changelog":"- Updated documentation to refer to the ContextMint Bridge browser extension instead of the now-renamed Transporter/fetchproxy extension. - Added installation instructions and verification steps for ContextMint Bridge, with relevant links and clarifications about Chrome/Safari compatibility. - Removed the obsolete skill-card.md file. - No changes to core functionality: querying hemnet.se via fpx works as before.","fileCount":4,"zipByteSize":5735},{"version":"1.1.5","createdAt":"2026-09-25T15:52:28.686Z","changelog":"- Removed the file skill-card.md. - No changes to the skill behavior or documentation content. - This update is for internal cleanup only.","fileCount":4,"zipByteSize":5512},{"version":"1.1.4","createdAt":"2026-09-23T21:40:24.171Z","changelog":"- Removed the skill-card.md file. - No user-facing functionality changes.","fileCount":4,"zipByteSize":5699}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:hemnet-fpx","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:hemnet-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/hemnet-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-hemnet-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-fpx/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-fpx/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-fpx/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-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-10T11:52:49.009Z"}},"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-hemnet-fpx/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-fpx/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-fpx/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-hemnet-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-10T09:43:13.291Z","emptyReason":null},"readme":"Skill: hemnet-fpx\n\nOwner: chrischall\n\nSummary: Query hemnet.se (Swedish property portal) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve locations, search for-sale and sold listings, and read listing detail via one-shot GraphQL calls through a signed-in browser tab. Use when you want Hemnet data without the MCP, in a script, or on a machine where the MCP isn't installed.\n\nTags: latest:1.1.11\n\nVersion history:\n\nv1.1.11 | 2026-10-09T23:26:26.737Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing changes; documentation and usage remain the same.\n\nv1.1.10 | 2026-10-07T13:35:14.784Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation except for this file removal.\n\nv1.1.9 | 2026-10-05T02:50:47.696Z | auto\n\n- Removed the file skill-card.md.\n- No changes to functionality or documentation content.\n\nv1.1.8 | 2026-10-03T01:41:36.008Z | auto\n\n- Removed the file: skill-card.md.\n- No other functional or user-facing changes.\n\nv1.1.7 | 2026-10-01T18:25:08.370Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation content.\n\nv1.1.6 | 2026-09-28T13:55:23.329Z | auto\n\n- Updated documentation to refer to the ContextMint Bridge browser extension instead of the now-renamed Transporter/fetchproxy extension.\n- Added installation instructions and verification steps for ContextMint Bridge, with relevant links and clarifications about Chrome/Safari compatibility.\n- Removed the obsolete skill-card.md file.\n- No changes to core functionality: querying hemnet.se via fpx works as before.\n\nv1.1.5 | 2026-09-25T15:52:28.686Z | auto\n\n- Removed the file skill-card.md.\n- No changes to the skill behavior or documentation content.\n- This update is for internal cleanup only.\n\nv1.1.4 | 2026-09-23T21:40:24.171Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing functionality changes.\n\nv1.1.3 | 2026-09-23T15:40:58.381Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing or functional changes to existing documentation or behavior.\n\nv1.1.2 | 2026-09-21T05:03:04.044Z | auto\n\n- Removed the skill-card.md file.\n- No functional changes to the skill itself.\n\nv1.1.1 | 2026-09-21T04:13:00.659Z | auto\n\n- Removed the file skill-card.md.\n- No changes to functionality or documentation in SKILL.md.\n\nv1.1.0 | 2026-09-20T02:49:36.418Z | auto\n\n- Removed the skill card documentation file (skill-card.md).\n- No changes to functionality or usage; this is a documentation clean-up release.\n\nv1.0.0 | 2026-09-19T11:19:49.650Z | auto\n\n- Removed the skill-card.md file.\n- No changes to core functionality or documentation content.\n\nv0.6.5 | 2026-09-17T17:50:03.303Z | auto\n\n- Removed the file: skill-card.md\n- No user-facing feature or documentation changes in this release.\n\nv0.6.4 | 2026-09-15T19:22:48.157Z | auto\n\n- Removed the file skill-card.md from the repository.\n- No changes to functionality or documentation other than file removal.\n\nv0.6.3 | 2026-09-14T14:10:26.040Z | auto\n\n- Removed the skill-card.md file.\n- No functional or user-facing changes; maintenance cleanup only.\n\nv0.6.2 | 2026-09-10T17:49:38.908Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation within SKILL.md.\n\nv0.6.1 | 2026-09-09T21:16:11.507Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing feature changes.\n\nv0.6.0 | 2026-09-04T22:22:01.376Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing feature changes.\n- Documentation and functionality remain unchanged.\n\nv0.5.0 | 2026-09-02T23:33:47.593Z | auto\n\n- Removed the sample file skill-card.md.\n- No user-facing, functional, or documentation changes.\n\nv0.4.0 | 2026-08-29T13:54:04.638Z | auto\n\n- Removed the skill-card.md file.\n- No functional or user-facing changes; only documentation file cleanup.\n\nv0.3.3 | 2026-08-28T21:07:21.929Z | auto\n\n- Removed the file skill-card.md.\n- No changes to functionality or documentation other than file removal.\n\nv0.3.2 | 2026-08-06T00:43:22.141Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation in SKILL.md.\n\nv0.3.1 | 2026-07-30T12:54:14.036Z | auto\n\n- Added comprehensive SKILL.md documentation for setup, usage, and troubleshooting of Hemnet querying via the fpx CLI.\n- Explains how to fetch property data from hemnet.se using a signed-in browser tab, without requiring the MCP server.\n- Details step-by-step onboarding, GraphQL query examples, and required tools/extensions.\n- Documents exit codes, restrictions, and usability notes to help users integrate Hemnet data scripts more easily.\n\nArchive index:\n\nArchive v1.1.11: 4 files, 5812 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (2037b), SKILL.md (3825b), _meta.json (130b)\n\nFile v1.1.11:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\n[its releases](https://github.com/nullnet-app/contextmint-bridge/releases) —\nChrome: load the chrome zip unpacked; Safari isn't available yet, so use\nChrome for now), with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\nContextMint Bridge is the renamed fetchproxy extension (same maintainer; source at https://github.com/nullnet-app/contextmint-bridge — verify a release zip with `shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.11:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.11\",\n  \"publishedAt\": 1791588386737\n}\n\nFile v1.1.11:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.11:skill-card.md\n\n## Description:\n\nGuides agents to query public Hemnet property listings and sold prices through a user-approved browser bridge and the fpx CLI.\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 and agents use this skill to resolve Swedish locations, search public for-sale and sold listings, and inspect property details without running an MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Installing an untrusted CLI or browser extension may expose browser activity.\n\nMitigation: Confirm you trust @fetchproxy/cli and ContextMint Bridge before installing; verify the extension release checksum.\n\nRisk: Broad site access or persistent pairing can allow unintended future browser requests.\n\nMitigation: Limit browser site access to hemnet.se and remove the pairing when no longer needed.\n\nRisk: A successful request may still contain GraphQL errors or too few sold listings for reliable comparisons.\n\nMitigation: Check the response for errors and the sold-listing count before using price summaries.\n\n## Reference(s):\n\n- [Hemnet GraphQL query examples](references/graphql-queries.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON, Guidance]\n\n**Output Format:** [Markdown instructions and GraphQL JSON responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Public Hemnet data only; prices in SEK and areas in m².]\n\n## Skill Version(s):\n\n1.1.11 (source: server-resolved ClawHub release)\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.10: 4 files, 5751 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (1957b), SKILL.md (3825b), _meta.json (130b)\n\nFile v1.1.10:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\n[its releases](https://github.com/nullnet-app/contextmint-bridge/releases) —\nChrome: load the chrome zip unpacked; Safari isn't available yet, so use\nChrome for now), with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\nContextMint Bridge is the renamed fetchproxy extension (same maintainer; source at https://github.com/nullnet-app/contextmint-bridge — verify a release zip with `shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.10:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.10\",\n  \"publishedAt\": 1791380114784\n}\n\nFile v1.1.10:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.10:skill-card.md\n\n## Description:\n\nGuides agents to resolve Swedish locations and query Hemnet's public for-sale, sold, and property-detail data using the fpx CLI and a paired browser extension 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\nDevelopers and agents use this skill to look up Swedish property listings and sale comparisons from a shell or script without running the Hemnet MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Installing a CLI and browser extension introduces third-party software with persistent bridge access.\n\nMitigation: Verify the @fetchproxy/cli package and ContextMint Bridge release, limit Chrome site access to hemnet.se, and remove the profile or extension when no longer needed.\n\nRisk: Querying Hemnet may conflict with the site's usage terms.\n\nMitigation: Confirm the intended use complies with Hemnet's terms before querying.\n\n## Reference(s):\n\n- [Hemnet GraphQL query examples](references/graphql-queries.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n- [ContextMint Bridge source](https://github.com/nullnet-app/contextmint-bridge)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance, Configuration instructions]\n\n**Output Format:** [Markdown with shell commands and GraphQL JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Hemnet query results are JSON; property prices are in SEK and areas in m².]\n\n## Skill Version(s):\n\n1.1.10 (source: server-resolved 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.9: 4 files, 5692 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (1839b), SKILL.md (3825b), _meta.json (129b)\n\nFile v1.1.9:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\n[its releases](https://github.com/nullnet-app/contextmint-bridge/releases) —\nChrome: load the chrome zip unpacked; Safari isn't available yet, so use\nChrome for now), with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\nContextMint Bridge is the renamed fetchproxy extension (same maintainer; source at https://github.com/nullnet-app/contextmint-bridge — verify a release zip with `shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.9:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.9\",\n  \"publishedAt\": 1791168647696\n}\n\nFile v1.1.9:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.9:skill-card.md\n\n## Description:\n\nHelps agents query public Hemnet property listings from a shell using the fpx CLI and a user-approved browser bridge 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\nDevelopers and agents use this skill to resolve Swedish locations, search for-sale and sold Hemnet properties, and retrieve listing details through anonymous browser-mediated queries.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Installing the CLI and browser extension adds third-party software and browser access.\n\nMitigation: Verify the package and extension release sources, and restrict extension site access to hemnet.se.\n\nRisk: Queries could exceed the disclosed anonymous property-data use.\n\nMitigation: Use only anonymous public Hemnet property queries and follow hemnet.se's terms.\n\n## Reference(s):\n\n- [Hemnet fpx skill release](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n- [GraphQL query examples](artifact/references/graphql-queries.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Code, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON query examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Queries return public listing data, with prices in SEK and areas in m².]\n\n## Skill Version(s):\n\n1.1.9 (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.8: 4 files, 5704 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (1856b), SKILL.md (3825b), _meta.json (129b)\n\nFile v1.1.8:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\n[its releases](https://github.com/nullnet-app/contextmint-bridge/releases) —\nChrome: load the chrome zip unpacked; Safari isn't available yet, so use\nChrome for now), with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\nContextMint Bridge is the renamed fetchproxy extension (same maintainer; source at https://github.com/nullnet-app/contextmint-bridge — verify a release zip with `shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.8:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1790991696008\n}\n\nFile v1.1.8:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.8:skill-card.md\n\n## Description:\n\nGuides agents in querying public Hemnet property listings and sales from a shell through a domain-scoped browser bridge.\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 and other agents can resolve Swedish locations, search public for-sale and sold properties, and inspect listings without running an MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Using the skill requires trusting an external CLI and browser extension.\n\nMitigation: Review the extension source or verify its release checksum before installation and pairing.\n\nRisk: Overbroad browser access or use beyond public Hemnet reads may exceed the intended scope.\n\nMitigation: Limit the CLI profile and extension site access to hemnet.se, and follow Hemnet's terms for public reads.\n\n## Reference(s):\n\n- [Hemnet GraphQL query examples](references/graphql-queries.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, Code, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON GraphQL query bodies]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Public listing results can include prices in SEK and areas in m²; check responses for GraphQL errors.]\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, 5722 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (1860b), SKILL.md (3825b), _meta.json (129b)\n\nFile v1.1.7:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\n[its releases](https://github.com/nullnet-app/contextmint-bridge/releases) —\nChrome: load the chrome zip unpacked; Safari isn't available yet, so use\nChrome for now), with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\nContextMint Bridge is the renamed fetchproxy extension (same maintainer; source at https://github.com/nullnet-app/contextmint-bridge — verify a release zip with `shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.7:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.7\",\n  \"publishedAt\": 1790879108370\n}\n\nFile v1.1.7:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.7:skill-card.md\n\n## Description:\n\nGuides agents in querying public Hemnet property listings from a shell using the fpx CLI and a scoped browser bridge, 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\nDevelopers and agents use this skill to resolve Swedish locations, search active and sold Hemnet listings, and inspect listing details through a browser-backed CLI.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Installing a global CLI and browser extension grants a browser bridge access to requests.\n\nMitigation: Verify the extension release, restrict its profile and site access to hemnet.se, and approve pairing deliberately.\n\nRisk: Automated property queries could exceed acceptable use of Hemnet's public data.\n\nMitigation: Limit use to public property reads consistent with Hemnet's terms.\n\n## Reference(s):\n\n- [GraphQL query examples](artifact/references/graphql-queries.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n- [Hemnet FPX on ClawHub](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Code, Guidance]\n\n**Output Format:** [Text and Markdown with shell and GraphQL examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Queries return public listing data as JSON, with prices in SEK and areas in square meters.]\n\n## Skill Version(s):\n\n1.1.7 (source: ClawHub 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.6: 4 files, 5735 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (1873b), SKILL.md (3825b), _meta.json (129b)\n\nFile v1.1.6:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\n[its releases](https://github.com/nullnet-app/contextmint-bridge/releases) —\nChrome: load the chrome zip unpacked; Safari isn't available yet, so use\nChrome for now), with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\nContextMint Bridge is the renamed fetchproxy extension (same maintainer; source at https://github.com/nullnet-app/contextmint-bridge — verify a release zip with `shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.6:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.6\",\n  \"publishedAt\": 1790603723329\n}\n\nFile v1.1.6:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.6:skill-card.md\n\n## Description:\n\nHelps agents query Hemnet property listings and sold prices with one-shot GraphQL calls through a paired browser tab 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\nDevelopers and other users can resolve Swedish locations, search for-sale and sold properties, and inspect listing details from a shell without running the Hemnet MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Requests use a browser bridge with persistent pairing to reach Hemnet through the user's browser context.\n\nMitigation: Use a Hemnet-scoped profile and remove the pairing or extension access when no longer needed.\n\nRisk: Browser-routed queries bypass Hemnet's Cloudflare challenge.\n\nMitigation: Review Hemnet's terms and the browser-bridge workflow before use.\n\n## Reference(s):\n\n- [Hemnet GraphQL query examples](references/graphql-queries.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Code, Guidance]\n\n**Output Format:** [Markdown with shell commands and GraphQL JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Query results are JSON; monetary values are in SEK and areas in m². Check GraphQL errors even when the request succeeds.]\n\n## Skill Version(s):\n\n1.1.6 (source: ClawHub 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.5: 4 files, 5512 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (1828b), SKILL.md (3399b), _meta.json (129b)\n\nFile v1.1.5:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.5:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.5\",\n  \"publishedAt\": 1790351548686\n}\n\nFile v1.1.5:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.5:skill-card.md\n\n## Description:\n\nGuides agents in querying public Hemnet property listings and sold prices from a shell using fpx and a paired browser tab 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\nDevelopers and agents use this skill to resolve Swedish locations, find for-sale and sold homes, and inspect listing details through public Hemnet queries without running an MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The global fpx CLI and paired Transporter extension bridge requests through the user's browser.\n\nMitigation: Review both before installation, restrict extension site access to hemnet.se, and approve pairing only for the intended browser.\n\nRisk: Queries to Hemnet could exceed the scope of intended public-data access.\n\nMitigation: Use anonymous public property-data reads only and follow Hemnet's terms.\n\n## Reference(s):\n\n- [Hemnet GraphQL query examples](references/graphql-queries.md)\n- [hemnet-fpx on ClawHub](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Configuration instructions, Guidance]\n\n**Output Format:** [Markdown with shell commands and GraphQL JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Explains how to inspect JSON results, including GraphQL errors returned with HTTP 200.]\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, 5699 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (2343b), SKILL.md (3399b), _meta.json (129b)\n\nFile v1.1.4:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.4:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.4\",\n  \"publishedAt\": 1790199624171\n}\n\nFile v1.1.4:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.4:skill-card.md\n\n## Description:\n\nQuery Hemnet property data from a shell with the fpx CLI, including location lookup, active listing search, sold listing search, and listing detail requests through browser-backed GraphQL calls.\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 and agents use this skill to prepare shell commands and GraphQL request bodies for retrieving public Hemnet property listings without running the Hemnet MCP server. It is suited for scripted property searches, listing inspection, and sold-price comparisons where the user controls the browser-backed fetch proxy.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Persistent fpx pairing can allow later commands to use the user's browser-backed access to hemnet.se.\n\nMitigation: Install and pair only trusted @fetchproxy/cli and Transporter extension instances, and run only Hemnet queries the user intends to make.\n\nRisk: Automated access to Hemnet may be subject to Hemnet terms or upstream limits.\n\nMitigation: Use the skill for anonymous public reads, keep requests proportionate, and follow Hemnet's terms.\n\nRisk: GraphQL responses can include errors even when the HTTP request succeeds.\n\nMitigation: Check the response for a GraphQL errors array before relying on returned listing data.\n\n## Reference(s):\n\n- [Hemnet GraphQL query examples](references/graphql-queries.md)\n- [Hemnet GraphQL endpoint](https://www.hemnet.se/graphql)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with shell commands, JSON GraphQL request bodies, and jq filters]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces instructions and request examples; commands run only when the user or agent executes them.]\n\n## Skill Version(s):\n\n1.1.4 (source: server 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, 5655 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (2189b), SKILL.md (3399b), _meta.json (129b)\n\nFile v1.1.3:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.3:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.3\",\n  \"publishedAt\": 1790178058381\n}\n\nFile v1.1.3:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.3:skill-card.md\n\n## Description:\n\nQuery hemnet.se from a shell with the fpx CLI to resolve locations, search for-sale and sold listings, and read listing details through one-shot GraphQL calls routed through a signed-in browser tab.\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 and engineers use this skill to query public Hemnet property data from shell workflows without running the Hemnet MCP server. It helps prepare fpx profiles, issue GraphQL requests, inspect listings, and compute simple sold-listing summaries.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The workflow depends on the fpx CLI, the Transporter browser extension, and a paired browser profile.\n\nMitigation: Install and pair those components only in an environment where you trust the local browser-extension and CLI setup.\n\nRisk: GraphQL responses may include an errors array even when the HTTP request succeeds.\n\nMitigation: Check the response for GraphQL errors before using returned listing data.\n\nRisk: The skill queries Hemnet through a user's browser session and Hemnet tab.\n\nMitigation: Use anonymous public-property queries only and stay within hemnet.se terms.\n\n## Reference(s):\n\n- [Hemnet GraphQL queries for fpx](references/graphql-queries.md)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n- [Hemnet GraphQL endpoint](https://www.hemnet.se/graphql)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, markdown, shell commands, configuration]\n\n**Output Format:** [Markdown with shell commands, JSON GraphQL request bodies, and jq examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces instructions and command snippets; it does not execute requests directly.]\n\n## Skill Version(s):\n\n1.1.3 (source: server 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.2: 4 files, 5551 bytes\n\nFiles: references/graphql-queries.md (5046b), skill-card.md (2047b), SKILL.md (3399b), _meta.json (129b)\n\nFile v1.1.2:SKILL.md\n\n---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the Transporter\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in Transporter\n```\n\nRequirements: the **Transporter** browser extension installed, with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort\n```\n\n## Exit codes (fetch verbs)\n\n- `0` — success (a GraphQL `errors` array can still ride in a `0` body; check it).\n- `2` — bridge unavailable: extension not connected or pairing pending → run `fpx pair -p hemnet`, confirm a hemnet tab is open.\n- `3` — bot wall: the tab hasn't cleared Cloudflare → open/refresh a `www.hemnet.se` tab and retry.\n- `4` — upstream non-2xx from Hemnet.\n\n## Notes\n\n- Anonymous reads only — this touches the same public GraphQL surface as the\n  MCP; no account data. Stay within hemnet.se's terms.\n- `fpx health -p hemnet` shows bridge connection state when a call fails.\n- This project is developed and maintained by AI (Claude).\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1789966984044\n}\n\nFile v1.1.2:references/graphql-queries.md\n\n# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name } brokerAgency { name } coordinates { lat long } images(limit: $photoLimit) { total images { url(format: ITEMGALLERY_L) } } } } }\",\n  \"variables\": { \"id\": \"21625405\", \"photoLimit\": 5 }\n}\n```\n\n```sh\njq '.data.listing | {addr: .streetAddress, price: .askingPrice.formatted, rooms: .numberOfRooms, m2: .livingArea, photos: [.images.images[].url]}'\n```\n\n## 4. Search sold listings (slutpriser — the comps)\n\nSame filter shape as §2 but the input type is `SaleSearchInput!`, the result\nis `searchSales { total cards }`, and money fields are pre-formatted **strings**\n(not `Money` objects). `sort` is `SaleSearchSorting` (`NEWEST`/`OLDEST`).\n\n```json\n{\n  \"query\": \"query Sold($search: SaleSearchInput!, $limit: Int!, $sort: SaleSearchSorting) { searchSales(search: $search, limit: $limit, sort: $sort) { total cards { id streetAddress finalPrice askingPrice priceChange soldAtLabel livingArea rooms squareMeterPrice } } }\",\n  \"variables\": { \"search\": { \"locationIds\": [\"898675\"] }, \"limit\": 25, \"sort\": \"NEWEST\" }\n}\n```\n\n```sh\n# Median final price across the sold cards (strip \"kr\" and spaces):\njq -r '[.data.searchSales.cards[].finalPrice | gsub(\"[^0-9]\";\"\") | tonumber] | sort | .[length/2|floor]'\n```\n\n## 5. Sold listing detail by id\n\n`soldListing` returns `SoldPropertyListing` — note the renamed fields\n(`sellingPrice`, `squareMeterSellingPrice`, `hemnetUrl`; no `region`).\n\n```json\n{\n  \"query\": \"query GetSold($id: ID!) { soldListing(id: $id) { __typename ... on SoldPropertyListing { streetAddress area numberOfRooms livingArea soldAt hemnetUrl sellingPrice { formatted } askingPrice { formatted } squareMeterSellingPrice { formatted } tenure { name } broker { name } } } }\",\n  \"variables\": { \"id\": \"REPLACE_WITH_SOLD_ID\" }\n}\n```\n\n---\n\n## Market stats\n\nHemnet has no market-stats query — the `hemnet_get_market_stats` tool derives\nmedian/average final price and price-per-m² locally from a `searchSales` page\n(§4). Reproduce with `jq` over the `cards` as shown above; check the card\ncount before trusting a thin median.\n\nFile v1.1.2:skill-card.md\n\n## Description:\n\nQuery hemnet.se from a shell with the fpx CLI to resolve locations, search for-sale and sold listings, and retrieve listing details through a signed-in browser tab.\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 and agents use this skill to produce fpx shell commands, GraphQL request bodies, and jq checks for retrieving public Hemnet listing data without running the hemnet-mcp server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill depends on the fpx CLI and Transporter browser extension to query Hemnet through a signed-in browser tab.\n\nMitigation: Confirm the fpx CLI and Transporter extension are trusted before use, and keep Chrome site access limited to hemnet.se.\n\nRisk: The skill queries public Hemnet data through Hemnet's GraphQL endpoint.\n\nMitigation: Use the skill only for public Hemnet data and follow Hemnet's terms.\n\nRisk: Hemnet GraphQL responses can include an errors array even when the HTTP request succeeds.\n\nMitigation: Check GraphQL errors with jq before relying on listing, sold-listing, or market-stat results.\n\n## Reference(s):\n\n- [Hemnet GraphQL queries for fpx](references/graphql-queries.md)\n- [Hemnet GraphQL endpoint](https://www.hemnet.se/graphql)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, JSON, Configuration]\n\n**Output Format:** [Markdown with inline shell commands and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes fpx commands, GraphQL request bodies, jq filters, setup notes, and exit-code interpretation.]\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.","readmeExcerpt":"Skill: hemnet-fpx Owner: chrischall Summary: Query hemnet.se (Swedish property portal) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve locations, search for-sale and sold listings, and read listing detail via one-shot GraphQL calls through a signed-in browser tab. Use when you want Hemnet data without the MCP, in a script, or on a machine where the MCP isn't installe","codeSnippets":[],"executableExamples":[{"language":"sh","snippet":"npm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge"},{"language":"sh","snippet":"fpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'"},{"language":"sh","snippet":"printf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/q.json -p hemnet \\\n  | jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName)\"'\n# 898675  Höllviken tätort"},{"language":"sh","snippet":"cat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'"},{"language":"json","snippet":"{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}"},{"language":"sh","snippet":"jq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: hemnet-fpx\ndescription: >-\n  Query hemnet.se (Swedish property portal) from a shell with the fpx CLI\n  (@fetchproxy/cli) instead of running the hemnet-mcp server — resolve\n  locations, search for-sale and sold listings, and read listing detail via\n  one-shot GraphQL calls through a signed-in browser tab. Use when you want\n  Hemnet data without the MCP, in a script, or on a machine where the MCP\n  isn't installed.\n---\n\n# Hemnet via fpx (no MCP)\n\nHemnet fronts `www.hemnet.se` — including `/graphql` — with a Cloudflare\nmanaged challenge that 403s any plain `curl`/Node request. `fpx` routes the\nrequest through the user's own signed-in browser tab (the ContextMint Bridge\nextension), which has already cleared the challenge, so the same anonymous\nGraphQL query succeeds. No Hemnet login is needed — just a normal open tab.\n\nThis is the same data the `hemnet_*` MCP tools return (money in **SEK**\nstrings, areas in **m²**), reached with one CLI call instead of a running\nserver.\n\n## One-time setup\n\n```sh\nnpm install -g @fetchproxy/cli            # provides `fpx`\nfpx profile add hemnet --domain hemnet.se # only the fetch capability is needed\nfpx pair -p hemnet                        # prints a pair code → approve in ContextMint Bridge\n```\n\nRequirements: the **ContextMint Bridge** browser extension installed (from\n[its releases](https://github.com/nullnet-app/contextmint-bridge/releases) —\nChrome: load the chrome zip unpacked; Safari isn't available yet, so use\nChrome for now), with an open\n`www.hemnet.se` tab, and its Chrome **Site access** allowing `hemnet.se`.\nPairing persists — after the first approval every later `fpx` call reuses it.\nContextMint Bridge is the renamed fetchproxy extension (same maintainer; source at https://github.com/nullnet-app/contextmint-bridge — verify a release zip with `shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).\n\n## Core call\n\nEvery query is a POST of `{\"query\": \"...\", \"variables\": {...}}` to the\nGraphQL endpoint. Send the body raw (no `--json`) so stdout is the GraphQL\nJSON, ready for `jq`:\n\n```sh\nfpx post-json 'https://www.hemnet.se/graphql' @query.json -p hemnet \\\n  | jq '.data'\n```\n\n`@file` reads the body from a file; a literal `'{...}'` string works too but\nshell-quoting the embedded query is fiddly — prefer a heredoc into a file.\n\nReady-to-run query bodies (autocomplete, for-sale search, listing detail,\nsold search) with jq recipes are in `references/graphql-queries.md`. Exhaustive\nfield lists live in the repo at `src/graphql.ts` — the operations here are\ncompact, live-verified subsets.\n\n## The one rule: resolve the location first\n\nHemnet searches take numeric **location ids**, never place names. Always\nautocomplete first, take the `locationId`, then search:\n\n```sh\nprintf '{\"query\":\"query($q:String!,$l:Int!){autocompleteLocations(query:$q,limit:$l){hits{locationId fullName parentFullName}}}\",\"variables\":{\"q\":\"Höllviken\",\"l\":3}}' > /tmp/q.json\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"hemnet-fpx\",\n  \"version\": \"1.1.11\",\n  \"publishedAt\": 1791588386737\n}"},{"path":"references/graphql-queries.md","content":"# Hemnet GraphQL queries for fpx\n\nReady-to-run bodies for `fpx post-json 'https://www.hemnet.se/graphql' @file -p hemnet`.\nEach block is the full POST body (`{\"query\",\"variables\"}`). All field names\nand input shapes are live-verified; the exhaustive field selections live in\nthe repo at `src/graphql.ts` (these are compact subsets).\n\nEndpoint: `https://www.hemnet.se/graphql` · Method: POST · anonymous.\n\nWrite the body to a file (heredoc avoids shell-quoting the GraphQL string),\nthen send it:\n\n```sh\ncat > /tmp/hq.json <<'JSON'\n{ \"query\": \"…\", \"variables\": { … } }\nJSON\nfpx post-json 'https://www.hemnet.se/graphql' @/tmp/hq.json -p hemnet | jq '.data'\n```\n\nAlways check for GraphQL errors: `jq '.errors // empty'` (an errors array can\nride in an HTTP-200 body).\n\n---\n\n## 1. Resolve a location → locationId (do this first)\n\n`variables.query` is free text; `limit` is required (`Int!`).\n\n```json\n{\n  \"query\": \"query Autocomplete($query: String!, $limit: Int!) { autocompleteLocations(query: $query, limit: $limit) { hits { locationId fullName parentFullName } } }\",\n  \"variables\": { \"query\": \"Höllviken\", \"limit\": 5 }\n}\n```\n\n```sh\njq -r '.data.autocompleteLocations.hits[] | \"\\(.locationId)\\t\\(.fullName) — \\(.parentFullName)\"'\n```\n\n## 2. Search for-sale listings\n\n`search.locationIds` is an array of strings (from step 1). Optional filters:\n`priceMin`/`priceMax` (SEK), `roomsMin`/`roomsMax`, `livingAreaMin`/`livingAreaMax`\n(m²), `keywords` (string), `housingFormGroups` (array of `HOUSES`, `APARTMENTS`,\n`ROW_HOUSES`, `VACATION_HOMES`, `PLOTS`, `OTHERS`). `limit` is required; `sort`\nis `NEWEST` or `OLDEST`.\n\n```json\n{\n  \"query\": \"query Search($search: ListingSearchForSaleInput!, $limit: Int!, $sort: ListingSearchForSaleSorting) { searchForSaleListings(search: $search, limit: $limit, sort: $sort) { total listings { id streetAddress area numberOfRooms livingArea listingHemnetUrl askingPrice { amount formatted } fee { formatted } squareMeterPrice { formatted } } } }\",\n  \"variables\": {\n    \"search\": { \"locationIds\": [\"898675\"], \"housingFormGroups\": [\"HOUSES\"], \"priceMax\": 10000000 },\n    \"limit\": 10,\n    \"sort\": \"NEWEST\"\n  }\n}\n```\n\n```sh\njq -r '.data.searchForSaleListings | \"total=\\(.total)\", (.listings[] | \"\\(.id)\\t\\(.askingPrice.formatted)\\t\\(.streetAddress)\")'\n```\n\n## 3. Listing detail by id\n\n`id` from a search card (`ID!`); `photoLimit` required (`Int!`). `listing`\nreturns the `PropertyListing` interface — the detail fields sit behind the\n`... on ActivePropertyListing` fragment. A non-active id yields\n`__typename` ≠ `ActivePropertyListing` (use the sold query in §5 instead).\n\n```json\n{\n  \"query\": \"query GetListing($id: ID!, $photoLimit: Int!) { listing(id: $id) { __typename ... on ActivePropertyListing { streetAddress area numberOfRooms livingArea legacyConstructionYear description listingHemnetUrl askingPrice { formatted } fee { formatted } runningCosts { formatted } squareMeterPrice { formatted } tenure { name } energyClassification { classification } broker { name "},{"path":"skill-card.md","content":"## Description:\n\nGuides agents to query public Hemnet property listings and sold prices through a user-approved browser bridge and the fpx CLI.\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 and agents use this skill to resolve Swedish locations, search public for-sale and sold listings, and inspect property details without running an MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Installing an untrusted CLI or browser extension may expose browser activity.\n\nMitigation: Confirm you trust @fetchproxy/cli and ContextMint Bridge before installing; verify the extension release checksum.\n\nRisk: Broad site access or persistent pairing can allow unintended future browser requests.\n\nMitigation: Limit browser site access to hemnet.se and remove the pairing when no longer needed.\n\nRisk: A successful request may still contain GraphQL errors or too few sold listings for reliable comparisons.\n\nMitigation: Check the response for errors and the sold-listing count before using price summaries.\n\n## Reference(s):\n\n- [Hemnet GraphQL query examples](references/graphql-queries.md)\n- [ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/hemnet-fpx)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON, Guidance]\n\n**Output Format:** [Markdown instructions and GraphQL JSON responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Public Hemnet data only; prices in SEK and areas in m².]\n\n## Skill Version(s):\n\n1.1.11 (source: server-resolved ClawHub release)\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":1348,"uniquenessScore":44,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T09:43:13.291Z","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-10T09:43:13.291Z","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-10T11:52:49.012Z","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"}]}}}