{
 "$schema": "https://agentdrives.com/schemas/tool.schema.json",
 "id": "prd_01m57vgtmfkhg6e946h35k97gx",
 "ids": {
  "org": "org_01m57vgtmfndxqy1rd1bp0wzwv",
  "surfaces": {
   "web": "srf_01m5km2y27t88k1kn4xgg9r6j1",
   "api": "srf_01m5km2y27q6jvtmy7dgs63rhm",
   "mcp": "srf_01m5km2y27czgvsvn2gt4hb2nv"
  },
  "slugs": [
   "bookstackapp"
  ],
  "domain": "bookstackapp.com",
  "wikidata": "Q107122654"
 },
 "slug": "bookstackapp",
 "name": "BookStack",
 "url": "https://bookstackapp.com",
 "domain": "bookstackapp.com",
 "category": "workspace",
 "category_name": "Docs and workspace",
 "tested_at": "2026-10-23",
 "run": "20261023T050151Z",
 "draft": false,
 "reviewed": true,
 "owner_verified": null,
 "origin": "editorial",
 "history": [
  {
   "run": "20261023T050151Z",
   "date": "2026-10-23",
   "level": 4,
   "engine": {
    "runner": "omp",
    "model": "claude-opus-5-5",
    "driver": 4,
    "signed": true,
    "inbox": [
     "agentdrives.com"
    ],
    "robots": "skip"
   },
   "stop": null
  }
 ],
 "level": 4,
 "level_name": "Runs on its own",
 "level_selfhost": null,
 "entry": "self-start",
 "door": {
  "passed": 1,
  "tries": 1,
  "self_start": true
 },
 "badges": [
  "agent-can-leave"
 ],
 "not_counted": null,
 "stages": [
  {
   "key": "in",
   "label": "Access",
   "state": "yes",
   "text": "Gets in on its own: no key needed",
   "way": "keyless"
  },
  {
   "key": "work",
   "label": "Use",
   "state": "yes",
   "text": "Work done: 100% of the core"
  },
  {
   "key": "pay",
   "label": "Pay",
   "state": "part",
   "text": "Reaches the checkout: stopped at the €559.01 a year charge",
   "value": "checkout",
   "route": "card_checkout"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "yes",
   "text": "Leaves on its own: nothing to cancel, deletes its account",
   "left": "deleted",
   "delete": {
    "state": "yes",
    "text": "Deletes its account",
    "why": null
   }
  }
 ],
 "outcomes": [
  {
   "key": "find",
   "label": "Learn",
   "state": "part",
   "text": "Docs with gaps: no getting-started page",
   "have": [],
   "docs": "gaps"
  },
  {
   "key": "access",
   "label": "Access",
   "state": "yes",
   "text": "Gets in on its own: no key needed",
   "way": "keyless",
   "stage": "in"
  },
  {
   "key": "use",
   "label": "Use",
   "state": "yes",
   "text": "Work done: 100% of the core",
   "stage": "work"
  },
  {
   "key": "pay",
   "label": "Pay",
   "state": "part",
   "text": "Reaches the checkout: stopped at the €559.01 a year charge",
   "value": "checkout",
   "route": "card_checkout",
   "stage": "pay"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "yes",
   "text": "Leaves on its own: nothing to cancel, deletes its account",
   "left": "deleted",
   "delete": {
    "state": "yes",
    "text": "Deletes its account",
    "why": null
   },
   "stage": "leave"
  }
 ],
 "access": [
  {
   "key": "keyless",
   "label": "No key needed",
   "routes": [
    "keyless"
   ],
   "minutes": 4,
   "core": "10/10"
  }
 ],
 "minutes": 4,
 "next": {
  "to": 5,
  "text": "Next: pay without a person"
 },
 "stop": null,
 "core": "10/10",
 "scores": {
  "coverage": 87,
  "reliability": 96,
  "resilience": 63,
  "setup": 30,
  "surface_coverage": null,
  "docs_accuracy": null,
  "docs_completeness": null
 },
 "parts": {
  "holds_up": 80,
  "docs_match": null,
  "setup": 30,
  "security": null,
  "standards": []
 },
 "reliability_method": "pass^k",
 "resilience": {
  "parts": {
   "error_legibility": 90,
   "recovery": 100,
   "idempotency": 0
  },
  "summary": {
   "error_legibility": "clear",
   "recovery": "good",
   "idempotency": "risky",
   "rate_limits": "none-seen",
   "notes": "Errors are JSON {error:{code,message,validation}} with the right status (422 names the field, 404, 401). 15 quick reads all returned 200 (x-ratelimit-limit 180, legacy X- headers). A repeated create duplicates, and some unknown fields are ignored without an error."
  }
 },
 "stress": [
  {
   "capability": "Create a page",
   "probe": "page create without book_id/chapter_id",
   "outcome": "422 application/json {\"error\":{\"message\":\"The given data was invalid.\",\"validation\":{\"book_id\":[\"The book id field is required when chapter id is not present.\"],\"chapter_id\":[\"The chapter id field is ",
   "grade": "clear",
   "idempotent": null,
   "rate_limit": null
  },
  {
   "capability": "Read a page, chapter or book",
   "probe": "read a page id that does not exist",
   "outcome": "404 {\"error\":{\"message\":\"Page not found.\",\"code\":404}}",
   "grade": "clear",
   "idempotent": null,
   "rate_limit": null
  },
  {
   "capability": "Create a book",
   "probe": "bad type: tags as a string",
   "outcome": "422 {\"error\":{\"message\":\"The given data was invalid.\",\"validation\":{\"tags\":[\"The tags must be an array.\"]},\"code\":422}}",
   "grade": "clear",
   "idempotent": null,
   "rate_limit": null
  },
  {
   "capability": "Create a book",
   "probe": "same create twice with Idempotency-Key",
   "outcome": "200 id=83; 200 id=84",
   "grade": "clear",
   "idempotent": "no",
   "rate_limit": null
  },
  {
   "capability": "credentials",
   "probe": "wrong token",
   "outcome": "401 {\"error\":{\"message\":\"No matching API token was found for the provided authorization token\",\"code\":401}}",
   "grade": "clear",
   "idempotent": null,
   "rate_limit": null
  },
  {
   "capability": "Read a page, chapter or book",
   "probe": "15 quick GET /api/system",
   "outcome": "statuses=[200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200]; x-ratelimit-remaining=['149', '148', '147', '146', '145', '144', '143', '142', '141', '140', '139', '179', '178', ",
   "grade": "clear",
   "idempotent": null,
   "rate_limit": "none-seen"
  },
  {
   "capability": "Import content from a Portable ZIP export",
   "probe": "interrupt the import between upload and run",
   "outcome": "upload 200 id=4; newest books meanwhile=[(65, 'AgentDrives Test Book 1792732236 (renamed)'), (61, 'AgentDrives Test Book 1792732236 (renamed)'), (8, 'Marketing Depertment'), (7, 'Sales Department'), (",
   "grade": "clear",
   "idempotent": null,
   "rate_limit": null
  }
 ],
 "surface_audit": null,
 "coverage_core": 100,
 "coverage_own": 100,
 "after_wall": null,
 "coverage_source": "computed",
 "driver": {
  "version": 4,
  "model": "claude-opus-5-5",
  "profile": "full",
  "assisted": false,
  "handoff": false,
  "prompt_sha": "4557b0885929",
  "kb_version": "3+overlay-1c6cbb2182",
  "identity": "e8a92f24a9a8"
 },
 "methodology": 24,
 "rules_date": "2026-10-20",
 "engine": {
  "runner": "omp",
  "model": "claude-opus-5-5",
  "driver": 4,
  "signed": true,
  "inbox": [
   "agentdrives.com"
  ],
  "robots": "skip"
 },
 "same_level_drives": 1,
 "drives": 1,
 "same_stop_drives": 1,
 "works_assisted": null,
 "freshness": "fresh",
 "newer_drives": null,
 "nothing_to_pay": false,
 "core_gated": false,
 "profiles": {},
 "agent_check": null,
 "agent_pass": null,
 "who_gets_in": {
  "server": {
   "state": "in"
  },
  "signed": {
   "state": "page",
   "kind": "signup",
   "at": "2026-10-23"
  },
  "browser": {
   "state": "in",
   "measured": false
  },
  "our_key": "pending",
  "robots": null,
  "tip": false
 },
 "ladder": {
  "docs": {
   "status": "headless",
   "note": "User and admin docs on www.bookstackapp.com/docs (fresh, dated). The API reference lives only inside each instance at /api/docs; the demo's robots.txt (User-agent: * Disallow: /) closes it to crawlers, so we read its source on the GitHub mirror. No llms.txt, no OpenAPI, no markdown versions."
  },
  "signup": {
   "status": "n/a",
   "note": "There is no hosted sign-up: BookStack is self-hosted only. The vendor's public demo (demo.bookstackapp.com) publishes a shared admin login on its home page, and it got us in with no form, CAPTCHA or email.",
   "way": "keyless"
  },
  "verify": {
   "status": "n/a",
   "note": "No email step on the demo login."
  },
  "credentials": {
   "status": "browser",
   "note": "API tokens are made only in the profile UI (My Account > Access & Security > API Tokens). The secret is shown once. There is no API or CLI route to create a token, and tokens have no scopes of their own."
  },
  "first_call": {
   "status": "headless",
   "note": "GET /api/system and GET /api/books with Authorization: Token id:secret returned 200.",
   "route": "account"
  },
  "first_action": {
   "status": "headless",
   "note": "POST /api/books created a book (id 61); GET read it back."
  },
  "pay": {
   "status": "browser",
   "grade": "P2",
   "rails": [
    "Stripe Checkout"
   ],
   "rail_ids": [
    "stripe-checkout"
   ],
   "first_party": false,
   "rail_scope": "none",
   "trial_path": "free tier",
   "3ds": "none",
   "route": "card_checkout",
   "checkout": {
    "reached": "card_form",
    "processor": "stripe_checkout",
    "captcha": "invisible",
    "three_ds": "not_seen",
    "card_form": true,
    "phone_field": "none",
    "wallets": [
     "apple_pay",
     "link"
    ],
    "rail_offer": "none",
    "price": "559.01",
    "currency": "EUR",
    "period": "year",
    "plan": "BookStack Professional Support Plan (£450/year)",
    "last_button": "Subscribe with obligation to pay"
   },
   "person": "none",
   "ours": "no_card",
   "note": "BookStack itself is free. The only purchase is a support plan from HTTP Functions Ltd: register at the support portal (no CAPTCHA), accept the terms, then Stripe Checkout with a card form or Apple Pay/Link. We stopped at the card form because we have no card. No x402, MPP or billing API (nothing paid)."
  },
  "cancel": {
   "status": "n/a",
   "note": "Nothing to cancel: our agent used the free plan.",
   "docs_note": "Nothing to cancel: no plan was started. Subscribers get a 'Manage billing' button (Stripe billing portal) in the support portal.",
   "docs_grade": "",
   "nothing": "free_plan"
  },
  "delete": {
   "status": "browser",
   "note": "Through the API we deleted every book, chapter, page, shelf, role, import and recycle-bin entry we made. In the UI we deleted our webhook and sort rule and revoked our token (401 afterwards). The demo login is shared, so it is not ours to delete, and the demo resets every half hour. The support-portal account from the checkout walk has no delete control: only by mail to its staff, which we did not send.",
   "left": "deleted",
   "after_hours": null,
   "account": true
  }
 },
 "routes": [
  {
   "route": "keyless",
   "offered": "documented",
   "tried": true,
   "not_tried": null,
   "result": "in",
   "wall": null,
   "person": "none",
   "brings": "nothing",
   "fresh": true,
   "minutes": 4,
   "browser": true
  },
  {
   "route": "local",
   "offered": "documented",
   "tried": false,
   "not_tried": "policy",
   "result": null,
   "wall": null,
   "person": null,
   "brings": null,
   "fresh": null,
   "minutes": null,
   "browser": null
  },
  {
   "route": "sso_enterprise",
   "offered": "documented",
   "tried": false,
   "not_tried": "assisted_only",
   "result": null,
   "wall": null,
   "person": null,
   "brings": null,
   "fresh": null,
   "minutes": null,
   "browser": null
  }
 ],
 "checkout": {
  "reached": "card_form",
  "processor": "stripe_checkout",
  "captcha": "invisible",
  "three_ds": "not_seen",
  "phone_field": "none",
  "wallets": [
   "apple_pay",
   "link"
  ],
  "rail_offer": "none",
  "period": "year",
  "card_form": true,
  "price": "559.01",
  "currency": "EUR",
  "plan": "BookStack Professional Support Plan (£450/year)",
  "last_button": "Subscribe with obligation to pay"
 },
 "docs": {
  "at": "2026-10-23",
  "read": 50,
  "listed": 50,
  "sampled": false,
  "overall": "gaps",
  "getting_started": "missing",
  "auth": "found",
  "errors": "partial",
  "examples": "good",
  "freshness": "fresh",
  "newest": "2026-10-23",
  "core_pages": "9 of 10",
  "capabilities": "most"
 },
 "claims": {
  "claimed": 9,
  "tried": 9,
  "held": 9,
  "broken": 0,
  "unclear": 0,
  "not_tried": 0,
  "undocumented_works": 0
 },
 "pay_options": {
  "checked": "2026-10-23",
  "source": "probe",
  "options": [],
  "agentic": [],
  "paid": null,
  "exercised": null,
  "detected_grade": null,
  "trial": {
   "no_card": null,
   "card_required": null,
   "free_plan": null
  },
  "owner_fixes": [
   {
    "title": "Accept x402 or MPP on your API",
    "how": "Answer an unpaid call with 402 and a payment challenge, so an agent pays per call or buys credits without an account or a card."
   },
   {
    "title": "List your plans on Stripe Projects",
    "how": "Agents buy a plan with `stripe projects add`, paid with a token under a spend cap the owner sets (projects.dev)."
   }
  ]
 },
 "surfaces": {
  "api": true,
  "openapi": false,
  "cli": false,
  "sdk": false,
  "mcp": "none",
  "llms_txt": false,
  "webhooks": true,
  "sandbox": true
 },
 "surface_notes": {
  "api": "REST, per instance at /api; token auth; books, chapters, pages, shelves, attachments, comments, images, imports, exports, search, users, roles, content permissions, recycle bin, audit log. No webhooks or tokens endpoints.",
  "openapi": "none; own docs.json format at /api/docs.json",
  "webhooks": "outgoing webhooks, configured in the UI only",
  "sandbox": "public demo instance reset every half hour"
 },
 "can_do": [
  "Create, read, update, move and delete books, chapters, pages and shelves through the REST API",
  "Write and edit page content as HTML or Markdown through the API",
  "Export a page as plain text, Markdown, HTML or PDF, and a book as a Portable ZIP",
  "Import a Portable ZIP back as a new book through the API",
  "Search across all content by keyword through the API",
  "Tag pages, add link attachments, set role permissions on content and create roles through the API",
  "Restore a deleted item from the recycle bin through the API",
  "Read the audit log through the API",
  "In the web UI: restore an old page revision, mark a page as a template, add a diagrams.net drawing, create a webhook and an auto-sort rule"
 ],
 "cannot_do": [
  {
   "what": "Create an API token without a browser",
   "why": "Tokens are made only in the profile UI; no API or CLI route"
  },
  {
   "what": "Create webhooks through the API",
   "why": "POST /api/webhooks answers 405; webhooks are UI-only"
  },
  {
   "what": "Set a book's sort rule through the API",
   "why": "PUT /api/books/{id} with sort_rule_id returns 200 but ignores it"
  },
  {
   "what": "Configure SSO (OIDC, SAML2, LDAP)",
   "why": "Set in the server's .env file; not reachable without a server"
  },
  {
   "what": "Use a hosted account of its own",
   "why": "No hosted BookStack: self-hosted only, plus a shared public demo"
  }
 ],
 "blockers": [
  "API tokens only from the web UI",
  "API reference only inside each instance (/api/docs); the demo's robots.txt closes it to crawlers"
 ],
 "tips_for_agents": [
  "There is no hosted BookStack: use your own instance, or the public demo at demo.bookstackapp.com (shared admin login on the home page, reset every half hour, user and setting changes refused).",
  "Create the API token in My Account > Access & Security. The secret is shown once, so capture it on the same page load.",
  "Auth header: Authorization: Token <id>:<secret>. Send JSON with Content-Type set. List endpoints take count, offset, sort and filter[field:op].",
  "Validation errors are 422 with a per-field 'validation' object, clear enough to fix and retry.",
  "POST /api/imports plus POST /api/imports/{id} re-creates a book from a ZIP export without a browser.",
  "Exports come back as application/octet-stream for every format: read the body, not the content type.",
  "Unknown body fields are ignored silently (e.g. sort_rule_id on books): read back what you set.",
  "No Idempotency-Key support: a retried create duplicates."
 ],
 "selfhost": {
  "install": {
   "status": "skipped",
   "minutes": 0,
   "note": "no docker in the drive sandbox; BookStack is self-hosted (docs/admin/installation)"
  }
 },
 "summary": "BookStack has no hosted sign-up: it is self-hosted, plus a public demo with a shared admin login. On that demo an agent drove every core task end to end through the REST API (books, chapters, pages, edits, moves, exports, ZIP import, search, delete and restore), three times each, all verified. The one browser step is making the API token. Webhooks, revisions, templates, drawings and sort rules are UI-only.",
 "wall": "",
 "plan_scope": "vendor's public demo instance (shared admin login; product is free open source)",
 "robots_stop": null,
 "robots": {
  "rule": "star",
  "step": null,
  "seen": "2026-10-23",
  "held": false
 },
 "terms": null,
 "plain": {
  "summary": "BookStack is a free, open-source wiki you run yourself; there's no company account to sign up for. The test used the vendor's public demo with its published shared login, and from there an agent did every core job itself through the API: creating, editing, organizing, exporting, searching, importing and deleting wiki content. It only needed a real browser to make its own access key and, at the end, to revoke that key and tidy up a couple of settings-only features.",
  "can_do": [
   "Create, edit, move, export, import, search, delete and restore wiki books, chapters and pages on its own",
   "Make its own access key and read the live wiki through it",
   "Tag content, attach links, set permissions and roles, and read the activity log"
  ],
  "cannot_do": [
   {
    "what": "Get an access key without opening a browser",
    "why": "Keys can only be created on the account settings page"
   },
   {
    "what": "Set up webhooks or automatic sorting through the API",
    "why": "Those are configured only in the web settings pages"
   },
   {
    "what": "Finish buying the paid support plan",
    "why": "Checkout needed a payment card, which the test didn't have"
   }
  ]
 },
 "plan_gated": [],
 "reply": null,
 "capabilities": [
  {
   "id": "cap-01",
   "capability": "Create a book",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/books",
    "mcp": null,
    "cli": null,
    "ui": "Books index > Create new book"
   },
   "check": "GET /api/books/{id} returns the new book",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/content-overview/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-02",
   "capability": "Create a chapter within a book",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/chapters",
    "mcp": null,
    "cli": null,
    "ui": "Book page > New Chapter"
   },
   "check": "GET /api/chapters/{id} returns the new chapter under the book",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/content-overview/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-03",
   "capability": "Create a page",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/pages",
    "mcp": null,
    "cli": null,
    "ui": "Book/Chapter > New Page"
   },
   "check": "GET /api/pages/{id} returns the new page content",
   "capability_id": "cap_yvyjytn1",
   "source": "https://www.bookstackapp.com/docs/user/content-overview/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-04",
   "capability": "Edit a page's content (WYSIWYG or Markdown)",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "PUT /api/pages/{id}",
    "mcp": null,
    "cli": null,
    "ui": "Page editor"
   },
   "check": "GET /api/pages/{id} shows updated html/markdown body",
   "capability_id": "cap_5wfd6v1f",
   "source": "https://www.bookstackapp.com/docs/user/markdown-editor/; https://www.bookstackapp.com/docs/user/wysiwyg-editor/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-05",
   "capability": "Read a page, chapter or book",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "GET /api/pages/{id}",
    "mcp": null,
    "cli": null,
    "ui": "Page/Book/Chapter view"
   },
   "check": "Response body matches the viewed content",
   "capability_id": "cap_5s4b1zbk",
   "source": "https://www.bookstackapp.com/docs/user/content-overview/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-06",
   "capability": "Delete or archive a page, chapter or book",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "DELETE /api/pages/{id}",
    "mcp": null,
    "cli": null,
    "ui": "Page actions > Delete (moves to recycle bin)"
   },
   "check": "GET /api/pages/{id} returns 404; item appears in Settings > Recycle Bin",
   "capability_id": "cap_bmyjwyc1",
   "source": "https://www.bookstackapp.com/docs/user/organising-content/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-07",
   "capability": "Organise content into books, chapters, bookshelves and move items",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "PUT /api/pages/{id} (chapter_id/book_id), POST /api/shelves",
    "mcp": null,
    "cli": null,
    "ui": "Page/Chapter 'Move' action; Book 'Sort' drag-and-drop view"
   },
   "check": "GET /api/pages/{id} shows the new parent chapter/book id",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/organising-content/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-08",
   "capability": "Export a page, chapter or book",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "GET /api/pages/{id}/export/pdf (also /html, /plaintext, /markdown)",
    "mcp": null,
    "cli": null,
    "ui": "Page/Chapter/Book 'Export' action"
   },
   "check": "Downloaded file (PDF/HTML/TXT/MD) contains the page content",
   "capability_id": "cap_7aee1e15",
   "source": "https://www.bookstackapp.com/docs/user/export-import/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-09",
   "capability": "Import content from a Portable ZIP export",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Books index > Import, or /import path"
   },
   "check": "Imported books/pages appear in the content tree after running the import",
   "capability_id": "cap_a8damn1w",
   "source": "https://www.bookstackapp.com/docs/user/export-import/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-10",
   "capability": "Search content across books, chapters and pages",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "GET /api/search",
    "mcp": null,
    "cli": null,
    "ui": "Header search bar; book/chapter sidebar search"
   },
   "check": "Search results list pages matching the query term",
   "capability_id": "cap_j1x1a2f4",
   "source": "https://www.bookstackapp.com/docs/user/searching/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-11",
   "capability": "Insert or edit a diagrams.net drawing in a page",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Page editor toolbar > drawing button"
   },
   "check": "Page content includes the embedded PNG drawing with diagrams.net data",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/diagrams/",
   "result": "done",
   "via": "browser"
  },
  {
   "id": "cap-12",
   "capability": "Upload a file or link attachment to a page",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/attachments",
    "mcp": null,
    "cli": null,
    "ui": "Page editor sidebar > attachments"
   },
   "check": "GET /api/attachments/{id} returns the uploaded file/link metadata",
   "capability_id": "cap_facpbh70",
   "source": "https://www.bookstackapp.com/docs/user/attachments/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-13",
   "capability": "Tag a book, chapter, page or shelf",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "PUT /api/pages/{id} (tags array)",
    "mcp": null,
    "cli": null,
    "ui": "Edit view / page editor sidebar > tags"
   },
   "check": "GET /api/pages/{id} tags array shows the applied name/value tag",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/tags/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-14",
   "capability": "Mark a page as a reusable template",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Page editor sidebar > templates tab > 'Page is a template'"
   },
   "check": "Page appears in the templates list when creating a new page",
   "capability_id": "cap_krfe97w8",
   "source": "https://www.bookstackapp.com/docs/user/page-templates/",
   "result": "done",
   "via": "browser"
  },
  {
   "id": "cap-15",
   "capability": "Include another page's content via an include tag",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Page editor {{@page_id}} syntax"
   },
   "check": "Viewing the page shows the dynamically fetched content from the referenced page",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/reusing-page-content/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-16",
   "capability": "Get a stable permalink to a page or page section",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Select text on a page > popup link box"
   },
   "check": "Copied link navigates to the specific page/section",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/content-permalinks/",
   "result": "done",
   "via": "browser"
  },
  {
   "id": "cap-17",
   "capability": "View page revision history and restore an earlier version",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Page 'Revisions' action"
   },
   "check": "Page content reverts to the selected historic revision",
   "capability_id": "cap_hamgpdbp",
   "source": "https://www.bookstackapp.com/docs/user/content-overview/",
   "result": "done",
   "via": "browser"
  },
  {
   "id": "cap-18",
   "capability": "Create and manage roles with content and system permissions",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/roles",
    "mcp": null,
    "cli": null,
    "ui": "Settings > Roles"
   },
   "check": "GET /api/roles/{id} shows the configured permissions",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/roles-and-permissions/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-19",
   "capability": "Override content-level permissions on a shelf, book, chapter or page",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "PUT /api/content-permissions/{type}/{id}",
    "mcp": null,
    "cli": null,
    "ui": "Item 'Permissions' action"
   },
   "check": "GET content-permissions endpoint reflects the custom role overrides",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/roles-and-permissions/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-20",
   "capability": "Invite and manage a user account",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/users",
    "mcp": null,
    "cli": null,
    "ui": "Settings > Users"
   },
   "check": "GET /api/users/{id} shows the created user",
   "capability_id": "cap_3w8sjh12",
   "source": "https://www.bookstackapp.com/docs/user/roles-and-permissions/",
   "result": "blocked",
   "via": "api"
  },
  {
   "id": "cap-21",
   "capability": "Configure SSO via LDAP, SAML2 or OIDC with group role-syncing",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Admin .env config / Settings > Authentication"
   },
   "check": "A login via the configured provider assigns the synced role to the user",
   "capability_id": "cap_pz4pecfg",
   "source": "https://www.bookstackapp.com/docs/admin/ldap-auth/; https://www.bookstackapp.com/docs/admin/saml2-auth/; https://www.bookstackapp.com/docs/admin/oidc-auth/",
   "result": "blocked",
   "via": null
  },
  {
   "id": "cap-22",
   "capability": "Enable multi-factor authentication for a user or role",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "User account settings > MFA; role-level enforcement in Settings > Roles"
   },
   "check": "Login requires a TOTP code or backup code after … entry",
   "capability_id": "cap_9qz744jy",
   "source": "https://www.bookstackapp.com/",
   "result": "not_tried",
   "via": null
  },
  {
   "id": "cap-23",
   "capability": "Register an outgoing webhook for content events",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/webhooks",
    "mcp": null,
    "cli": null,
    "ui": "Settings > Webhooks"
   },
   "check": "GET /api/webhooks/{id} shows the configured endpoint and triggering events",
   "capability_id": "cap_977hxacb",
   "source": "https://www.bookstackapp.com/docs/admin/email-webhooks/",
   "result": "done",
   "via": "browser"
  },
  {
   "id": "cap-24",
   "capability": "Restore a deleted item from the recycle bin",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "PUT /api/recycle-bin/{id}",
    "mcp": null,
    "cli": null,
    "ui": "Settings > Recycle Bin"
   },
   "check": "GET /api/pages/{id} (or equivalent) returns the restored item",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/organising-content/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-25",
   "capability": "Define a sort rule for automatic book ordering",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Settings > Sorting"
   },
   "check": "Newly created/updated content in the assigned book re-orders per the configured rule operations",
   "capability_id": null,
   "unmapped": "own_feature",
   "source": "https://www.bookstackapp.com/docs/user/organising-content/",
   "result": "done",
   "via": "browser"
  },
  {
   "id": "cap-26",
   "capability": "View the system-wide audit log",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "GET /api/audit-log",
    "mcp": null,
    "cli": null,
    "ui": "Settings > Audit Log"
   },
   "check": "Audit log lists the recent create/update/delete/login events",
   "capability_id": "cap_xgs80797",
   "source": "https://www.bookstackapp.com/",
   "result": "done",
   "via": "api"
  },
  {
   "id": "cap-27",
   "capability": "Switch between light and dark interface themes",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "User account preferences"
   },
   "check": "Interface colour scheme changes after toggling",
   "capability_id": null,
   "unmapped": "not_a_job",
   "source": "https://www.bookstackapp.com/",
   "result": "not_tried",
   "via": null
  },
  {
   "id": "cap-28",
   "capability": "Set the instance preferred language/locale",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "User account preferences / Settings"
   },
   "check": "Interface text renders in the chosen language",
   "capability_id": null,
   "unmapped": "not_a_job",
   "source": "https://www.bookstackapp.com/docs/admin/language-config/",
   "result": "not_tried",
   "via": null
  },
  {
   "id": "cap-29",
   "capability": "Customise instance branding (name, logo, colours)",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Settings > Customization"
   },
   "check": "Header/logo reflects the configured branding after save",
   "capability_id": "cap_28j5w4mh",
   "source": "https://www.bookstackapp.com/docs/admin/visual-customisation/",
   "result": "not_tried",
   "via": null
  },
  {
   "id": "cap-30",
   "capability": "Create an API token for a user",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "User profile > API Tokens"
   },
   "check": "The generated token authenticates subsequent API requests",
   "capability_id": "cap_wbg916v9",
   "source": "https://www.bookstackapp.com/docs/user/export-import/",
   "result": "done",
   "via": "browser"
  }
 ],
 "stale": false,
 "unreachable_since": null,
 "not_driven_since": null,
 "icon": "/logos/bookstackapp.png",
 "agent_kinds": {
  "browser": {
   "who": "An assistant in a browser",
   "passed": [
    "first_action"
   ],
   "stop": "pay",
   "why": "reaches the checkout, stopped at the €559.01 a year charge",
   "tone": "warn",
   "text": "Does all of the core work. Payment: reaches the checkout, stopped at the €559.01 a year charge."
  },
  "direct": {
   "who": "An agent talking to it directly",
   "passed": [],
   "stop": "credentials",
   "why": "the key comes only from a browser page",
   "tone": "wall",
   "text": "Stops at the API key: the key comes only from a browser page."
  }
 },
 "stop_evidence": null,
 "stop_shot": null,
 "attempts_count": 99,
 "detail": {
  "public": false,
  "in": [
   "report",
   "api"
  ],
  "since": "2026-10-17"
 },
 "what_it_does": "BookStack is a free, open-source wiki you run yourself.",
 "rules_version": "rules-2026-10-20-24",
 "rules_url": "https://agentdrives.com/method/changelog#rules-2026-10-20-24",
 "category_median": null,
 "verdict": null,
 "changes": {
  "source": "store",
  "drives": [
   {
    "run": "20261023T050151Z",
    "date": "2026-10-23",
    "level": 4,
    "stop": null,
    "entry": "self-start",
    "driver": 4,
    "listed": true
   }
  ],
  "events": [],
  "feed": "https://agentdrives.com/api/tools/bookstackapp/changes.json"
 },
 "agreement": null,
 "method_release": "2026-Q4.9",
 "rank": 1,
 "rank_of": 3,
 "rank_change": 0,
 "rank_since": "2026-10-24",
 "capability_matrix": [
  {
   "id": "cap-01",
   "name": "Create a book",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-02",
   "name": "Create a chapter within a book",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-03",
   "name": "Create a page",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-04",
   "name": "Edit a page's content (WYSIWYG or Markdown)",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-05",
   "name": "Read a page, chapter or book",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-06",
   "name": "Delete or archive a page, chapter or book",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-07",
   "name": "Organise content into books, chapters, bookshelves and move items",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-08",
   "name": "Export a page, chapter or book",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-09",
   "name": "Import content from a Portable ZIP export",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-10",
   "name": "Search content across books, chapters and pages",
   "core": true,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-11",
   "name": "Insert or edit a diagrams.net drawing in a page",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "done"
   }
  },
  {
   "id": "cap-12",
   "name": "Upload a file or link attachment to a page",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-13",
   "name": "Tag a book, chapter, page or shelf",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-14",
   "name": "Mark a page as a reusable template",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "done"
   }
  },
  {
   "id": "cap-15",
   "name": "Include another page's content via an include tag",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-16",
   "name": "Get a stable permalink to a page or page section",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "done"
   }
  },
  {
   "id": "cap-17",
   "name": "View page revision history and restore an earlier version",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "done"
   }
  },
  {
   "id": "cap-18",
   "name": "Create and manage roles with content and system permissions",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-19",
   "name": "Override content-level permissions on a shelf, book, chapter or page",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-20",
   "name": "Invite and manage a user account",
   "core": false,
   "result": "blocked",
   "surfaces": {
    "api": "blocked",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-21",
   "name": "Configure SSO via LDAP, SAML2 or OIDC with group role-syncing",
   "core": false,
   "result": "blocked",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-22",
   "name": "Enable multi-factor authentication for a user or role",
   "core": false,
   "result": "untried",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-23",
   "name": "Register an outgoing webhook for content events",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "untried",
    "mcp": "none",
    "cli": "none",
    "ui": "done"
   }
  },
  {
   "id": "cap-24",
   "name": "Restore a deleted item from the recycle bin",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-25",
   "name": "Define a sort rule for automatic book ordering",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "done"
   }
  },
  {
   "id": "cap-26",
   "name": "View the system-wide audit log",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "done",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-27",
   "name": "Switch between light and dark interface themes",
   "core": false,
   "result": "untried",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-28",
   "name": "Set the instance preferred language/locale",
   "core": false,
   "result": "untried",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-29",
   "name": "Customise instance branding (name, logo, colours)",
   "core": false,
   "result": "untried",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "untried"
   }
  },
  {
   "id": "cap-30",
   "name": "Create an API token for a user",
   "core": false,
   "result": "done",
   "surfaces": {
    "api": "none",
    "mcp": "none",
    "cli": "none",
    "ui": "done"
   }
  }
 ],
 "category_place": {
  "category": "workspace",
  "products": 5,
  "higher": 0,
  "same_level": 1,
  "as_of": "2026-10-23",
  "stop": null,
  "rivals_by": "level",
  "rivals": [
   "craft"
  ]
 },
 "page": "https://agentdrives.com/tools/bookstackapp?via=api"
}