Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/appicons/io.pilot.bowmark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/brand/apps/bowmark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions scripts/gen-apps.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const CAT_HUE = Object.fromEntries(CATEGORIES.map((c) => [c.id, c.hue]));
const CATMAP = {
'io.pilot.postgres': 'data', 'io.pilot.duckdb': 'data', 'io.pilot.redis': 'data', 'io.pilot.sixtyfour': 'data',
'io.pilot.cosift': 'ai', 'io.telepat.ideon-free': 'ai',
'io.pilot.plainweb': 'web', 'io.pilot.otto': 'web',
'io.pilot.plainweb': 'web', 'io.pilot.otto': 'web', 'io.pilot.bowmark': 'web',
'io.pilot.smolmachines': 'infra', 'io.pilot.miren': 'infra', 'io.pilot.docker': 'infra',
'io.pilot.aegis': 'security',
'io.pilot.slipstream': 'finance', 'io.pilot.wallet': 'finance',
Expand All @@ -55,6 +55,7 @@ const ICON_MAP = {
'io.pilot.wallet': { image: 'png', fit: 'contain', bg: '#ffffff' },
'io.telepat.ideon-free': { image: 'png', fit: 'cover', bg: '#0b0b0a' },
'io.pilot.aegis': { image: 'svg', fit: 'contain', bg: '#ffffff' },
'io.pilot.bowmark': { image: 'png', fit: 'cover', bg: '#0b0b0a' },
};

function relLum(hex) {
Expand Down Expand Up @@ -83,7 +84,7 @@ const APP_IDS = [
'io.pilot.postgres', 'io.pilot.duckdb', 'io.pilot.redis', 'io.pilot.sixtyfour',
'io.pilot.cosift', 'io.telepat.ideon-free', 'io.pilot.plainweb', 'io.pilot.otto',
'io.pilot.smolmachines', 'io.pilot.miren', 'io.pilot.docker', 'io.pilot.aegis',
'io.pilot.slipstream', 'io.pilot.wallet',
'io.pilot.slipstream', 'io.pilot.wallet', 'io.pilot.bowmark',
];
const FEATURED = ['io.pilot.postgres', 'io.pilot.duckdb', 'io.pilot.docker'];
const LINUX_ONLY = new Set(['io.pilot.docker']);
Expand Down
14 changes: 14 additions & 0 deletions src/data/app-methods.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
{
"io.pilot.bowmark": [
{
"name": "bowmark.ask",
"summary": "Look up a navigation recipe for a (site, task) pair \u2014 a URL shortcut or short UI procedure verified by prior crawls. status=ok \u2192 execute it open-loop; no_useful_data/site_not_supported \u2192 browse manually; ambiguous_scope \u2192 retry with scopeHint; rate_limited \u2192 back off. Pass variants:{auth_state:'logged_in'} for signed-in surfaces. Intent, not a URL."
},
{
"name": "bowmark.report_outcome",
"summary": "After running a recipe from ask, report how it executed (envelope_id, success, evidence). success=true only if every step ran as written; false on any retry, JS-eval fallback, or extra click. Feeds the re-crawl loop that keeps recipes healthy."
},
{
"name": "bowmark.help",
"summary": "Discovery: every method with params, kind, and latency class."
}
],
"io.pilot.docker": [
{
"name": "docker.engine_start",
Expand Down
51 changes: 51 additions & 0 deletions src/data/app-overrides.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,55 @@
{
"io.pilot.bowmark": {
"name": "Bowmark",
"tagline": "Navigation cheatsheets for public websites \u2014 recipes that skip explore-and-discover.",
"description": "Bowmark gives a browsing agent **pre-computed navigation recipes** for public websites \u2014 a parameterized URL `shortcut` or a short `ui_procedure` of UI steps, each verified by prior crawls. Instead of exploring and discovering a site's structure on every task (snapshotting the DOM, guessing selectors, burning tokens), the agent calls `ask({ site, task })` once and executes the returned recipe open-loop. On known sites that means roughly **5x fewer tokens** and far less latency.\n\n**Managed-key:** Pilot holds one shared Bowmark account behind the broker and meters each caller, so you install it **keyless** and never handle an API key. It's plain request/response REST \u2014 no websockets, no server-side browser, no async jobs. Your agent runs the recipe in its own browser; Bowmark only supplies the recipe.\n\n**Methods.** `bowmark.ask` \u2014 look up a recipe for a (site, task); on `status: ok` you get a URL `shortcut` (a `template` with `{name}` slots) and/or a `ui_procedure` of steps to run open-loop, plus an `id`. `bowmark.report_outcome` \u2014 after running a recipe, report whether it executed cleanly (`success` + `evidence`); this feeds the re-crawl loop that keeps recipes healthy, so report `false` on any deviation even if you still got the answer.\n\n**Syntax & edge cases.** `site` is a registrable domain, optionally with a product surface (`google.com`, `docs.stripe.com`, `google.com/maps`); `task` is intent, never a URL. Request the signed-in view with `variants: { auth_state: \"logged_in\", role: \"owner\" }` (also `locale` / `region` / `currency`). Non-`ok` statuses: `no_useful_data` / `site_not_supported` \u2192 browse manually; `ambiguous_scope` \u2192 retry with `scopeHint`; `rate_limited` \u2192 back off until `error.retry_after` (only new synthesis is capped). Skip it for localhost, RFC1918 IPs, and open-ended search with no destination.",
"vendor": "Bowmark AI",
"vendorUrl": "https://bowmark.ai",
"license": "Proprietary",
"sourceUrl": "https://github.com/bowmark-ai/plugin",
"homepage": "https://bowmark.ai",
"version": "0.1.0",
"categoriesRaw": [
"web",
"browser",
"automation"
],
"keywords": [
"browser",
"navigation",
"recipes",
"cheatsheets",
"websites",
"playwright",
"puppeteer",
"computer-use",
"scraping"
],
"bundleBytes": 5070051,
"installedBytes": 9105408,
"changelog": [
{
"version": "0.1.0",
"notes": [
"Initial release \u2014 managed-key REST adapter over the Bowmark API (bowmark.ask \u2192 /v1/ask, bowmark.report_outcome \u2192 /v1/outcomes).",
"One shared Bowmark account behind the Pilot broker, metered per caller; the installed adapter is keyless."
]
}
],
"minPilotVersion": "1.10.0",
"runtimes": [
"go"
],
"protection": "shareable",
"publishedAt": "2026-07-03",
"grants": [
"fs.read:$APP/config.json",
"key.sign:self",
"net.dial:broker.pilotprotocol.network",
"audit.log:*"
],
"inCatalogue": true
},
"io.pilot.docker": {
"name": "Docker",
"tagline": "Run Docker from an agent \u2014 a local Docker Engine + CLI on Linux, real containers",
Expand Down
96 changes: 96 additions & 0 deletions src/data/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,102 @@ export const apps: App[] = [
],
"publishedAt": "2026-06-08",
"updatedAt": "2026-06-08"
},
{
"id": "io.pilot.bowmark",
"name": "Bowmark",
"tagline": "Navigation cheatsheets for public websites — recipes that skip explore-and-discover",
"description": "Bowmark gives a browsing agent **pre-computed navigation recipes** for public websites — a parameterized URL `shortcut` or a short `ui_procedure` of UI steps, each verified by prior crawls. Instead of exploring and discovering a site's structure on every task (snapshotting the DOM, guessing selectors, burning tokens), the agent calls `ask({ site, task })` once and executes the returned recipe open-loop. On known sites that means roughly **5x fewer tokens** and far less latency.\n\n**Managed-key:** Pilot holds one shared Bowmark account behind the broker and meters each caller, so you install it **keyless** and never handle an API key. It's plain request/response REST — no websockets, no server-side browser, no async jobs. Your agent runs the recipe in its own browser; Bowmark only supplies the recipe.\n\n**Methods.** `bowmark.ask` — look up a recipe for a (site, task); on `status: ok` you get a URL `shortcut` (a `template` with `{name}` slots) and/or a `ui_procedure` of steps to run open-loop, plus an `id`. `bowmark.report_outcome` — after running a recipe, report whether it executed cleanly (`success` + `evidence`); this feeds the re-crawl loop that keeps recipes healthy, so report `false` on any deviation even if you still got the answer.\n\n**Syntax & edge cases.** `site` is a registrable domain, optionally with a product surface (`google.com`, `docs.stripe.com`, `google.com/maps`); `task` is intent, never a URL. Request the signed-in view with `variants: { auth_state: \"logged_in\", role: \"owner\" }` (also `locale` / `region` / `currency`). Non-`ok` statuses: `no_useful_data` / `site_not_supported` → browse manually; `ambiguous_scope` → retry with `scopeHint`; `rate_limited` → back off until `error.retry_after` (only new synthesis is capped). Skip it for localhost, RFC1918 IPs, and open-ended search with no destination.",
"categories": [
"web"
],
"primaryCategory": "web",
"keywords": [
"browser",
"navigation",
"recipes",
"cheatsheets",
"websites",
"playwright",
"puppeteer",
"computer-use",
"scraping"
],
"version": "0.1.0",
"vendor": "Bowmark AI",
"vendorUrl": "https://bowmark.ai",
"license": "Proprietary",
"sourceUrl": "https://github.com/bowmark-ai/plugin",
"homepage": "https://bowmark.ai",
"methods": [
{
"name": "bowmark.ask",
"summary": "Look up a navigation recipe for a (site, task) pair — a URL shortcut or short UI procedure verified by prior crawls. status=ok → execute it open-loop; no_useful_data/site_not_supported → browse manually; ambiguous_scope → retry with scopeHint; rate_limited → back off. Pass variants:{auth_state:'logged_in'} for signed-in surfaces. Intent, not a URL."
},
{
"name": "bowmark.report_outcome",
"summary": "After running a recipe from ask, report how it executed (envelope_id, success, evidence). success=true only if every step ran as written; false on any retry, JS-eval fallback, or extra click. Feeds the re-crawl loop that keeps recipes healthy."
},
{
"name": "bowmark.help",
"summary": "Discovery: every method with params, kind, and latency class."
}
],
"changelog": [
{
"version": "0.1.0",
"notes": [
"Initial release — managed-key REST adapter over the Bowmark API (bowmark.ask → /v1/ask, bowmark.report_outcome → /v1/outcomes).",
"One shared Bowmark account behind the Pilot broker, metered per caller; the installed adapter is keyless."
]
}
],
"grants": [
"fs.read:$APP/config.json",
"key.sign:self",
"net.dial:broker.pilotprotocol.network",
"audit.log:*"
],
"bundles": [
{
"platform": "darwin-arm64",
"bytes": 5374254
},
{
"platform": "darwin-amd64",
"bytes": 4968650
},
{
"platform": "linux-arm64",
"bytes": 5019350
},
{
"platform": "linux-amd64",
"bytes": 4613746
}
],
"installedBytes": 9105408,
"depends": [],
"protection": "shareable",
"featured": false,
"real": true,
"inCatalogue": true,
"icon": {
"mode": "image",
"img": "/appicons/io.pilot.bowmark.png",
"fit": "cover",
"pos": "center",
"color": "#0b0b0a",
"ink": false,
"file": null,
"hue": 200
},
"minPilotVersion": "1.10.0",
"runtimes": [
"go"
],
"publishedAt": "2026-07-03",
"updatedAt": "2026-07-03"
}
];

Expand Down
2 changes: 1 addition & 1 deletion src/pages/app-store.astro
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const canonicalUrl = 'https://pilotprotocol.network/app-store';
const featured = featuredApps();
const hero = featured[0];
const sideFeatured = featured.slice(1, 4);
const freshPinned = ['io.pilot.miren', 'io.pilot.smolmachines', 'io.pilot.wallet', 'io.pilot.slipstream'];
const freshPinned = ['io.pilot.bowmark', 'io.pilot.miren', 'io.pilot.smolmachines', 'io.pilot.wallet', 'io.pilot.slipstream'];
const freshExclude = new Set(['io.pilot.postgres', 'io.pilot.docker']);
const fresh = [
...freshPinned.map((id) => apps.find((a) => a.id === id)).filter(Boolean),
Expand Down
2 changes: 1 addition & 1 deletion src/pages/plain/app-store.astro
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
// Auto-generated by scripts/regen-plain.mjs. Edit the marketing source and re-run.
// plain-source: src/pages/app-store.astro
// plain-source-sha256: 64660b72f524cf3191438052d800df3205349be2e992faf75971fe0b979803e7
// plain-source-sha256: 38f6e44e971b262e6046c479d9ddeabc7ed10570d01e7536bd5ae11bda3d1fa7
import PlainLayout from '../../layouts/PlainLayout.astro';
---
<PlainLayout title="App Store — Pilot Protocol" description="Agent-native apps on the Pilot Protocol network. Install with one command; publish your own from your browser or by PR." canonical="https://pilotprotocol.network/plain/app-store/">
Expand Down
Loading