{
 "slug": "zulip",
 "name": "Zulip",
 "url": "https://zulip.com",
 "domain": "zulip.com",
 "category": "team-chat",
 "category_name": "Team chat",
 "tested_at": "2026-10-06",
 "run": "20261006T052730Z",
 "draft": false,
 "reviewed": true,
 "owner_verified": null,
 "origin": "editorial",
 "history": [
  {
   "run": "20261006T052730Z",
   "date": "2026-10-06",
   "level": 4,
   "engine": {
    "runner": "omp",
    "model": "claude-opus-5-5",
    "driver": 2,
    "signed": true,
    "inbox": [
     "agentdrives.com"
    ],
    "robots": "start"
   }
  }
 ],
 "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"
 ],
 "stages": [
  {
   "key": "in",
   "label": "Access",
   "state": "yes",
   "text": "Gets in on its own: sign-up in a browser"
  },
  {
   "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 card form",
   "value": "ready",
   "route": "card_checkout"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "yes",
   "text": "Leaves on its own: nothing to cancel, deletes its account",
   "left": "deleted"
  }
 ],
 "outcomes": [
  {
   "key": "find",
   "label": "Find",
   "state": "part",
   "text": "Some docs agents can read: an OpenAPI and an MCP server",
   "have": [
    "openapi",
    "mcp"
   ]
  },
  {
   "key": "access",
   "label": "Access",
   "state": "yes",
   "text": "Gets in on its own: sign-up in a browser",
   "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 card form",
   "value": "ready",
   "route": "card_checkout",
   "stage": "pay"
  },
  {
   "key": "leave",
   "label": "Leave",
   "state": "yes",
   "text": "Leaves on its own: nothing to cancel, deletes its account",
   "left": "deleted",
   "stage": "leave"
  }
 ],
 "access": [
  {
   "key": "browser_signup",
   "label": "Sign-up in a browser",
   "routes": [],
   "minutes": 5.6,
   "core": "7/7"
  }
 ],
 "minutes": 5.6,
 "next": {
  "to": 5,
  "text": "Next: pay without a person"
 },
 "stop": null,
 "core": "7/7",
 "scores": {
  "coverage": 91,
  "reliability": 90,
  "resilience": null,
  "setup": 70,
  "surface_coverage": null,
  "docs_accuracy": null,
  "docs_completeness": null
 },
 "parts": {
  "holds_up": null,
  "docs_match": null,
  "setup": 70,
  "security": null,
  "standards": [
   {
    "standard": "OpenAPI",
    "state": "behind",
    "behind": 2,
    "value": "3.0.1"
   }
  ]
 },
 "reliability_method": "first-try",
 "resilience": null,
 "stress": [],
 "surface_audit": null,
 "coverage_core": 100,
 "after_wall": null,
 "coverage_source": "computed",
 "driver": {
  "version": 2,
  "model": "claude-opus-5-5",
  "profile": "full",
  "assisted": false,
  "handoff": null,
  "prompt_sha": "f3d0adeeb256",
  "kb_version": "2+overlay-9e43028a2c",
  "identity": null
 },
 "methodology": 15,
 "rules_date": "2026-10-15",
 "engine": {
  "runner": "omp",
  "model": "claude-opus-5-5",
  "driver": 2,
  "signed": true,
  "inbox": [
   "agentdrives.com"
  ],
  "robots": "start"
 },
 "same_level_drives": 1,
 "drives": 1,
 "works_assisted": null,
 "freshness": "fresh",
 "nothing_to_pay": false,
 "core_gated": false,
 "profiles": {},
 "agent_check": null,
 "agent_pass": {
  "rung": "signup",
  "vendor": "ALTCHA proof-of-work (first-party widget, /json/antispam_challenge)",
  "signed": true
 },
 "who_gets_in": {
  "server": {
   "state": "in"
  },
  "signed": {
   "state": "page",
   "kind": "signup",
   "at": "2026-10-13"
  },
  "browser": {
   "state": "in",
   "measured": false
  },
  "our_key": "pending",
  "robots": null,
  "tip": false
 },
 "ladder": {
  "docs": {
   "status": "headless",
   "note": "zulip.com/api/ HTML docs; OpenAPI 3.0.1 (166 operations) in zulip/zulip on GitHub; no llms.txt, no markdown pages"
  },
  "signup": {
   "status": "browser",
   "note": "zulip.com/new/ carries an invisible ALTCHA proof-of-work; headless POST got 'Validation failed, please try again.'; in the browser the widget filled itself (~8 s, no challenge) and the second registration form posted headless"
  },
  "verify": {
   "status": "headless",
   "note": "Confirmation mail in ~30 s; do_confirm link and registration form posted with curl, no captcha"
  },
  "credentials": {
   "status": "headless",
   "note": "POST /api/v1/fetch_api_key with email+password",
   "via": ""
  },
  "first_call": {
   "status": "headless",
   "note": "GET /api/v1/users/me"
  },
  "first_action": {
   "status": "headless",
   "note": "Created a channel and posted a message, read back via GET /messages"
  },
  "pay": {
   "status": "browser",
   "grade": "P2",
   "rails": [
    "Stripe Checkout (card)",
    "pay by invoice"
   ],
   "rail_ids": [
    "stripe-checkout"
   ],
   "first_party": false,
   "rail_scope": "none",
   "trial_path": "free tier",
   "note": "No 402/x402/MPP or billing API; /upgrade leads to Stripe Checkout asking card, cardholder name and billing address, Stripe hCaptcha present with no visible challenge. Nothing paid."
  },
  "cancel": {
   "status": "n/a",
   "grade": "n/a",
   "note": "Nothing to cancel: our agent used the free plan.",
   "docs_note": "No paid plan started",
   "nothing": "free_plan"
  },
  "delete": {
   "status": "headless",
   "note": "POST /api/v1/realm/deactivate deletion_delay_days=14 (server minimum); API then 401 'This organization has been deactivated'; data permanently deleted on the 20 Oct 2026 MCP spec per confirmation mail",
   "left": "deleted",
   "account": true
  }
 },
 "routes": [],
 "checkout": null,
 "docs": null,
 "claims": null,
 "pay_options": {
  "checked": "2026-10-06",
  "source": "drive",
  "options": [
   {
    "id": "stripe-checkout",
    "name": "Stripe Checkout",
    "kind": "checkout",
    "first_party": false,
    "lead": false,
    "networks": [],
    "testnet": false
   }
  ],
  "agentic": [],
  "paid": null,
  "exercised": null,
  "detected_grade": null,
  "trial": {
   "no_card": null,
   "card_required": null,
   "free_plan": true
  },
  "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": true,
  "cli": true,
  "sdk": true,
  "mcp": "third-party",
  "llms_txt": false,
  "webhooks": true,
  "sandbox": false
 },
 "surface_notes": {
  "api": "REST, HTTP Basic email:key, 166 operations",
  "openapi": "3.0.1, on GitHub only, two paths in our map differed (reminders, linkifiers) but the spec was right",
  "sdk": "official Python package zulip 0.9.1 with zulip-send CLI",
  "mcp": "no official server; third-party stdio servers only"
 },
 "can_do": [
  "Post to channels/topics and send direct messages",
  "Create channels and organize topics, resolve topics",
  "Edit, delete and move messages between channels and topics",
  "Search message history",
  "Upload and share files",
  "Create a video call link in a conversation",
  "Create polls and to-do lists",
  "Schedule messages and reminders",
  "Manage drafts, snippets, status, notification settings and read state",
  "Create bots and incoming webhooks that post into channels",
  "Add linkifiers and custom profile fields",
  "Invite users, add guests, deactivate and reactivate users",
  "Set channel permissions and login methods",
  "Export organization data",
  "Deactivate the organization by API"
 ],
 "cannot_do": [
  {
   "what": "Create the organization headless",
   "why": "Sign-up form requires an ALTCHA proof-of-work that runs in the browser"
  },
  {
   "what": "User groups, retention, public access on Free",
   "why": "Zulip Cloud Standard only"
  },
  {
   "what": "Create users directly",
   "why": "POST /users needs server-level permission; invites work"
  },
  {
   "what": "Pay the agent way",
   "why": "Only Stripe Checkout with a card or invoice"
  }
 ],
 "blockers": [
  "Invisible ALTCHA proof-of-work on the sign-up form needs a JavaScript browser"
 ],
 "tips_for_owner": [
  "Document a way for agents to create organizations",
  "Publish llms.txt and Markdown API pages",
  "Serve the OpenAPI spec from zulip.com",
  "Offer a hosted MCP server",
  "List valid values in validation errors"
 ],
 "tips_for_agents": [
  "Do sign-up once in a real browser; ALTCHA solves itself, then POST /api/v1/fetch_api_key gives the key",
  "Use the OpenAPI on GitHub for exact routes: linkifiers are POST /realm/filters, reminders POST /reminders",
  "Download uploads via GET /api/v1/user_uploads/{path} (temporary URL), not the raw /user_uploads URL",
  "export_type is a string since feature level 449: 'public' or 'full_with_consent'",
  "Bot email is not in the POST /bots response; read it from GET /users/{id}"
 ],
 "selfhost": {
  "install": {
   "status": "skipped",
   "minutes": 0,
   "note": "no docker in the drive sandbox"
  }
 },
 "summary": "Zulip Cloud Free can be run almost entirely by an agent through its documented REST API: all 7 core capabilities and most secondary ones were done and read back, and the organization was deactivated by API. Only the sign-up form needs a browser, for an invisible ALTCHA proof-of-work that cleared on its own. No MCP, llms.txt or agent payment rail; paying is Stripe Checkout with a card.",
 "wall": "Sign-up form needs one browser visit",
 "plan_scope": "free plan",
 "robots_stop": null,
 "robots": null,
 "plain": {
  "summary": "Zulip is a team chat tool. An agent could sign up, send messages, manage channels, files, bots and admin settings, and later delete the whole organization, almost all through its documented programming interface. The only step needing a real browser was the sign-up form, and that passed on its own without any human help.",
  "can_do": [
   "Send and organize messages, channels and topics",
   "Edit, delete, move and search messages",
   "Share files and start video calls",
   "Create polls, to-do lists, reminders and scheduled messages",
   "Set up bots and incoming webhooks",
   "Invite, deactivate and reactivate users, and add guests",
   "Export all organization data",
   "Fully delete the organization and lose API access afterward"
  ],
  "cannot_do": [
   {
    "what": "Create the organization without any browser step",
    "why": "The sign-up form needs a hidden automatic browser check"
   },
   {
    "what": "Create user groups, set message retention, or turn on public access",
    "why": "Those need a paid plan"
   },
   {
    "what": "Pay for the paid plan like a program would",
    "why": "Only a human credit-card checkout page is offered"
   }
  ]
 },
 "plan_gated": [
  {
   "capability": "Create and manage custom user groups",
   "plan": "Zulip Cloud Standard",
   "evidence": "POST /user_groups/create -> 'Available on Zulip Cloud Standard. Upgrade to access.'"
  },
  {
   "capability": "Message retention policy",
   "plan": "Zulip Cloud Standard",
   "evidence": "PATCH /streams/{id} message_retention_days -> same error"
  },
  {
   "capability": "Public access (spectators)",
   "plan": "Zulip Cloud Standard",
   "evidence": "PATCH /realm enable_spectator_access -> same error"
  }
 ],
 "reply": null,
 "capabilities": [
  {
   "id": "cap-01",
   "group": "Collaboration basics",
   "capability": "Send a message to a channel/topic or as a direct message",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/messages",
    "mcp": null,
    "cli": null,
    "ui": "Compose box"
   },
   "check": "GET /api/v1/messages with narrow on the topic shows the new message content and id",
   "source": "https://zulip.com/api/send-message; https://zulip.com/help/send-a-message"
  },
  {
   "id": "cap-02",
   "group": "Collaboration basics",
   "capability": "Organize conversations into channels and topics",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/users/me/subscriptions (channels); topics are implicit on messages",
    "mcp": null,
    "cli": null,
    "ui": "Left sidebar channel/topic list"
   },
   "check": "GET /api/v1/streams and GET /api/v1/users/me/{stream_id}/topics list the created channel/topic",
   "source": "https://zulip.com/help/introduction-to-channels; https://zulip.com/help/introduction-to-topics; https://zulip.com/api/create-channel"
  },
  {
   "id": "cap-03",
   "group": "Collaboration basics",
   "capability": "Edit or delete a sent message",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "PATCH /api/v1/messages/{message_id}; DELETE /api/v1/messages/{message_id}",
    "mcp": null,
    "cli": null,
    "ui": "Message hover actions"
   },
   "check": "GET /api/v1/messages/{message_id}/history shows the edit, or the message id 404s after delete",
   "source": "https://zulip.com/api/update-message; https://zulip.com/api/delete-message"
  },
  {
   "id": "cap-04",
   "group": "Collaboration basics",
   "capability": "Move a message between channels or topics",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "PATCH /api/v1/messages/{message_id}",
    "mcp": null,
    "cli": null,
    "ui": "Message actions > Move message"
   },
   "check": "GET /api/v1/messages for the new narrow shows the message; old narrow no longer returns it",
   "source": "https://zulip.com/help/move-content-to-another-channel; https://zulip.com/help/move-content-to-another-topic"
  },
  {
   "id": "cap-05",
   "group": "Collaboration basics",
   "capability": "Search message history",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "GET /api/v1/messages (narrow with search operator)",
    "mcp": null,
    "cli": null,
    "ui": "Search bar"
   },
   "check": "GET /api/v1/messages with a search narrow returns matching messages (limited to 10,000 on Free cloud plan)",
   "source": "https://zulip.com/help/search-for-messages; https://zulip.com/api/get-messages"
  },
  {
   "id": "cap-06",
   "group": "Collaboration basics",
   "capability": "Share and store files/images in conversations",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/user_uploads",
    "mcp": null,
    "cli": null,
    "ui": "Compose box attachment button"
   },
   "check": "GET /api/v1/attachments lists the uploaded file and its URL resolves",
   "source": "https://zulip.com/help/share-and-upload-files; https://zulip.com/api/upload-file"
  },
  {
   "id": "cap-07",
   "group": "Collaboration basics",
   "capability": "Start a voice or video call from a conversation",
   "weight": "core",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/calls/bigbluebutton/create (and provider-specific endpoints)",
    "mcp": null,
    "cli": null,
    "ui": "Compose box call icon"
   },
   "check": "Call link is inserted into the compose box / message content referencing the created call",
   "source": "https://zulip.com/help/start-a-call; https://zulip.com/help/configure-call-provider"
  },
  {
   "id": "cap-08",
   "group": "Collaboration basics",
   "capability": "React to messages with emoji",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/messages/{message_id}/reactions",
    "mcp": null,
    "cli": null,
    "ui": "Message hover reaction icon"
   },
   "check": "GET /api/v1/messages/{message_id} shows reaction in the reactions array",
   "source": "https://zulip.com/api/add-reaction"
  },
  {
   "id": "cap-09",
   "group": "Efficient communication",
   "capability": "Schedule a message to send later",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/scheduled_messages",
    "mcp": null,
    "cli": null,
    "ui": "Compose box ellipsis > Schedule message"
   },
   "check": "GET /api/v1/scheduled_messages lists the message with its scheduled_delivery_timestamp, then appears in GET /api/v1/messages after delivery",
   "source": "https://zulip.com/help/schedule-a-message; https://zulip.com/api/create-scheduled-message"
  },
  {
   "id": "cap-10",
   "group": "Efficient communication",
   "capability": "Create a poll or collaborative to-do list in a message",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Compose box poll/to-do widget"
   },
   "check": "GET /api/v1/messages/{message_id} shows the widget submessage content with poll/to-do data",
   "source": "https://zulip.com/help/create-a-poll; https://zulip.com/help/collaborative-to-do-lists"
  },
  {
   "id": "cap-11",
   "group": "Efficient communication",
   "capability": "Schedule a reminder for yourself",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/messages/{message_id}/reminders",
    "mcp": null,
    "cli": null,
    "ui": "Message actions > Remind me"
   },
   "check": "GET /api/v1/reminders lists the created reminder with its delivery time",
   "source": "https://zulip.com/help/schedule-a-reminder; https://zulip.com/api/create-message-reminder"
  },
  {
   "id": "cap-12",
   "group": "Efficient communication",
   "capability": "Mark a topic as resolved",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/messages (topic rename to ✔ prefix) via update-message topic edit",
    "mcp": null,
    "cli": null,
    "ui": "Topic actions > Resolve"
   },
   "check": "GET topics in channel shows topic name prefixed with the resolved checkmark",
   "source": "https://zulip.com/help/resolve-a-topic"
  },
  {
   "id": "cap-13",
   "group": "Efficient communication",
   "capability": "Save and reuse message snippets",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/saved_snippets",
    "mcp": null,
    "cli": null,
    "ui": "Compose box saved snippet picker"
   },
   "check": "GET /api/v1/saved_snippets lists the saved snippet by title/content",
   "source": "https://zulip.com/help/saved-snippets; https://zulip.com/api/create-saved-snippet"
  },
  {
   "id": "cap-14",
   "group": "Efficient communication",
   "capability": "Save message drafts",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/drafts",
    "mcp": null,
    "cli": null,
    "ui": "Compose box auto-save / Drafts view"
   },
   "check": "GET /api/v1/drafts lists the draft content for the channel/topic",
   "source": "https://zulip.com/help/view-and-edit-your-message-drafts; https://zulip.com/api/create-drafts"
  },
  {
   "id": "cap-15",
   "group": "Efficient communication",
   "capability": "Set status, availability, and typing indicators",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/users/me/status; POST /api/v1/typing",
    "mcp": null,
    "cli": null,
    "ui": "User avatar menu > Set status"
   },
   "check": "GET /api/v1/users/{user_id}/status reflects the updated status text/emoji",
   "source": "https://zulip.com/help/status-and-availability; https://zulip.com/api/update-status"
  },
  {
   "id": "cap-16",
   "group": "Efficient communication",
   "capability": "Configure notification settings (DM, mention, alert words, email)",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "PATCH /api/v1/settings; POST /api/v1/users/me/alert_words",
    "mcp": null,
    "cli": null,
    "ui": "Settings > Notifications"
   },
   "check": "GET /api/v1/settings reflects changed notification flags",
   "source": "https://zulip.com/help/dm-mention-alert-notifications; https://zulip.com/help/email-notifications"
  },
  {
   "id": "cap-17",
   "group": "Efficient communication",
   "capability": "Mark messages/topics/channels as read or unread",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/mark_all_as_read; POST /api/v1/mark_stream_as_read; POST /api/v1/mark_topic_as_read",
    "mcp": null,
    "cli": null,
    "ui": "Inbox/message actions"
   },
   "check": "GET /api/v1/messages unread counts change after marking",
   "source": "https://zulip.com/help/marking-messages-as-unread; https://zulip.com/api/mark-all-as-read"
  },
  {
   "id": "cap-18",
   "group": "Efficient communication",
   "capability": "Get read receipts for a message",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "GET /api/v1/messages/{message_id}/read_receipts",
    "mcp": null,
    "cli": null,
    "ui": "Message actions > Read receipts"
   },
   "check": "Response lists user ids who have read the message",
   "source": "https://zulip.com/help/read-receipts; https://zulip.com/api/get-read-receipts"
  },
  {
   "id": "cap-19",
   "group": "Integrations",
   "capability": "Connect native and custom integrations/webhooks to post into channels",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "Outgoing/incoming webhook endpoints per integration; REST API",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Integrations"
   },
   "check": "Triggering the external event produces a bot-posted message visible via GET /api/v1/messages",
   "source": "https://zulip.com/integrations/; https://zulip.com/help/outgoing-webhooks; https://zulip.com/api/rest"
  },
  {
   "id": "cap-20",
   "group": "Integrations",
   "capability": "Create and manage bots for automation",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/users (bot_type); GET /api/v1/bots/{email}/api_key",
    "mcp": null,
    "cli": null,
    "ui": "Settings > Your bots"
   },
   "check": "GET /api/v1/users shows the new bot account with is_bot true",
   "source": "https://zulip.com/help/add-a-bot-or-integration; https://zulip.com/help/bots-overview"
  },
  {
   "id": "cap-21",
   "group": "Integrations",
   "capability": "Add custom linkifiers to auto-link text to external systems",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/realm/linkifiers",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Linkifiers"
   },
   "check": "GET /api/v1/realm/linkifiers lists the new pattern/URL template",
   "source": "https://zulip.com/help/add-a-custom-linkifier; https://zulip.com/api/add-linkifier"
  },
  {
   "id": "cap-22",
   "group": "Integrations",
   "capability": "Message a channel by sending email to it",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "GET /api/v1/streams/{stream_id}/email (to get address)",
    "mcp": null,
    "cli": null,
    "ui": "Channel settings > Email address"
   },
   "check": "Sending email to the channel address produces a message visible via GET /api/v1/messages",
   "source": "https://zulip.com/help/message-a-channel-by-email; https://zulip.com/api/get-stream-email-address"
  },
  {
   "id": "cap-23",
   "group": "Integrations",
   "capability": "Export organization data",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/export/realm",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Data exports"
   },
   "check": "GET /api/v1/export/realm lists the export job and a downloadable export URL when complete",
   "source": "https://zulip.com/help/export-your-organization; https://zulip.com/api/export-realm"
  },
  {
   "id": "cap-24",
   "group": "Integrations",
   "capability": "Import data from Slack, Teams, Mattermost, or Rocket.Chat",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": "./manage.py import (self-hosted)",
    "ui": "Import flow during org creation"
   },
   "check": "Imported channels/users/messages appear in the new Zulip organization",
   "source": "https://zulip.com/help/import-from-slack; https://zulip.com/help/import-from-microsoft-teams; https://zulip.com/help/migrating-from-other-chat-tools"
  },
  {
   "id": "cap-25",
   "group": "User administration",
   "capability": "Invite and manage users (invite links, deactivate, reactivate)",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/invites; POST /api/v1/users/{user_id}/reactivate; DELETE for deactivate",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Users"
   },
   "check": "GET /api/v1/users shows the new/updated user's is_active state",
   "source": "https://zulip.com/help/invite-new-users; https://zulip.com/api/create-user; https://zulip.com/api/deactivate-user"
  },
  {
   "id": "cap-26",
   "group": "User administration",
   "capability": "Create and manage custom user groups with permissions",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/user_groups/create",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > User groups"
   },
   "check": "GET /api/v1/user_groups lists the group with its members",
   "source": "https://zulip.com/help/create-user-groups; https://zulip.com/api/create-user-group"
  },
  {
   "id": "cap-27",
   "group": "User administration",
   "capability": "Add guest users with limited access",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/users (role: guest)",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Users > Invite"
   },
   "check": "GET /api/v1/users/{user_id} shows role corresponding to guest",
   "source": "https://zulip.com/help/guest-users"
  },
  {
   "id": "cap-28",
   "group": "User administration",
   "capability": "Set custom profile fields for users",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "POST /api/v1/realm/profile_fields",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Profile fields"
   },
   "check": "GET /api/v1/realm/profile_fields lists the new field definition",
   "source": "https://zulip.com/help/custom-profile-fields; https://zulip.com/api/create-custom-profile-field"
  },
  {
   "id": "cap-29",
   "group": "User administration",
   "capability": "Configure authentication methods (OAuth, SAML, SSO)",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Authentication methods"
   },
   "check": "Login page shows the enabled SSO/OAuth provider button",
   "source": "https://zulip.com/help/configure-authentication-methods; https://zulip.com/help/saml-authentication"
  },
  {
   "id": "cap-30",
   "group": "Advanced administration",
   "capability": "Set channel/message permissions (posting, editing, deleting, moving, access)",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "PATCH /api/v1/streams/{stream_id}",
    "mcp": null,
    "cli": null,
    "ui": "Channel settings > Permissions"
   },
   "check": "GET /api/v1/streams/{stream_id} shows updated permission fields",
   "source": "https://zulip.com/help/channel-permissions; https://zulip.com/help/channel-posting-policy; https://zulip.com/api/update-stream"
  },
  {
   "id": "cap-31",
   "group": "Advanced administration",
   "capability": "Set a message retention / data deletion policy",
   "weight": "secondary",
   "plan": "paid",
   "surfaces": {
    "api": "PATCH /api/v1/streams/{stream_id} (message_retention_days)",
    "mcp": null,
    "cli": null,
    "ui": "Organization/channel settings > Message retention"
   },
   "check": "GET /api/v1/streams/{stream_id} shows the configured message_retention_days",
   "source": "https://zulip.com/help/message-retention-policy"
  },
  {
   "id": "cap-32",
   "group": "Advanced administration",
   "capability": "View organization usage/analytics statistics",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Usage statistics"
   },
   "check": "Analytics page renders chart of message/user counts over time",
   "source": "https://zulip.com/help/analytics"
  },
  {
   "id": "cap-33",
   "group": "Advanced administration",
   "capability": "Customize organization branding (logo, name, description)",
   "weight": "peripheral",
   "plan": "paid",
   "surfaces": {
    "api": "PATCH /api/v1/realm",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Organization profile"
   },
   "check": "GET /api/v1/realm/icon or realm settings show the updated branding asset",
   "source": "https://zulip.com/help/create-your-organization-profile"
  },
  {
   "id": "cap-34",
   "group": "Advanced administration",
   "capability": "Set a custom domain for the organization",
   "weight": "peripheral",
   "plan": "paid",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Change organization URL"
   },
   "check": "Organization is reachable at the new custom domain",
   "source": "https://zulip.com/help/change-organization-url"
  },
  {
   "id": "cap-35",
   "group": "Advanced administration",
   "capability": "Enable public access option (read without an account)",
   "weight": "secondary",
   "plan": "free",
   "surfaces": {
    "api": "PATCH /api/v1/realm (enable_spectator_access)",
    "mcp": null,
    "cli": null,
    "ui": "Organization settings > Other settings"
   },
   "check": "Visiting the organization URL unauthenticated shows public channel content",
   "source": "https://zulip.com/help/public-access-option"
  },
  {
   "id": "cap-36",
   "group": "Account & billing",
   "capability": "Choose and upgrade a Zulip Cloud or self-hosted plan",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": null,
    "ui": "/plans and /upgrade"
   },
   "check": "Billing page shows the active plan tier after upgrade",
   "source": "https://zulip.com/plans/; https://zulip.com/help/zulip-cloud-billing"
  },
  {
   "id": "cap-37",
   "group": "Account & billing",
   "capability": "Install and use desktop, mobile, terminal, and web apps",
   "weight": "peripheral",
   "plan": "free",
   "surfaces": {
    "api": null,
    "mcp": null,
    "cli": "zulip-term",
    "ui": "/apps download page"
   },
   "check": "App login screen connects successfully to the organization realm",
   "source": "https://zulip.com/apps/"
  }
 ],
 "attempts": [
  {
   "t": "01:14",
   "cap": "discovery",
   "capability": "docs",
   "task": "Find API docs and OpenAPI",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "https://zulip.com/api/ 200 HTML docs; OpenAPI zerver/openapi/zulip.yaml in zulip/zulip GitHub (openapi: 3.0.1, 166 operationIds, server https://{subdomain}.zulipchat.com/api/v1)",
   "notes": "No llms.txt (zulip.com/llms.txt 404 JSON NONEXISTENT_SUBDOMAIN; /api/llms.txt 404). Accept: text/markdown returns text/html, no Vary: Accept; /api/send-message.md 404."
  },
  {
   "t": "01:14",
   "cap": "discovery",
   "capability": "agent discovery",
   "task": "Probe well-known agent/MCP/OAuth/payment files",
   "route": "api",
   "documented": true,
   "result": "failed",
   "verified": true,
   "evidence": "404 on /.well-known/ai-catalog.json, agent-card.json, agent.json, mcp/server-card.json, oauth-protected-resource, oauth-authorization-server, ucp; /auth.md, /SKILL.md 404; /robots.txt 404 (no rules, no Content-Usage)",
   "notes": "No official MCP server found in docs or search; only third-party ones (Monadical-SAS/zulip-mcp, akougkas/zulipchat-mcp, avisekrath/zulip-mcp-server), stdio, not hosted by Zulip."
  },
  {
   "t": "04:12",
   "cap": "signup",
   "capability": "sign up (create Zulip Cloud organization)",
   "task": "Fill https://zulip.com/new/ in the real browser and submit",
   "route": "browser",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Redirected to /accounts/new/send_confirm/?email=the agent's inbox&realm_subdomain=agentdrives-test-041: \"Confirm your email address\"",
   "notes": "Invisible ALTCHA proof-of-work widget (opacity 0) filled its captcha field on its own in the browser after ~8 s; no visible challenge, no interaction. A first submit without waiting came back with the form emptied."
  },
  {
   "t": "05:05",
   "cap": "credentials",
   "capability": "get API key",
   "task": "POST /api/v1/fetch_api_key with email+password",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "{\"result\":\"success\",\"user_id\":1211474,\"api_key\":\"••••\"}",
   "quality": {
    "docs_match": "match"
   }
  },
  {
   "t": "05:34",
   "cap": "first_call",
   "capability": "first API call",
   "task": "GET /api/v1/users/me",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "user_id 1211474, role 100 (owner); server 12.0-1057, feature level 511",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:34",
   "cap": "first_action",
   "capability": "first real action",
   "task": "Create a channel and post to it",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "stream_id 641750, message id 629431342, read back via GET /messages narrow",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:34",
   "cap": "cap-02",
   "capability": "Organize conversations into channels and topics",
   "task": "Create channel agentdrives-test and topic 'drive log'",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /users/me/subscriptions created channel; GET /get_stream_id -> 641750; GET /users/me/641750/topics lists 'drive log'",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:34",
   "cap": "cap-01",
   "capability": "Send a message to a channel/topic or as a direct message",
   "task": "Post to channel topic and a DM to self",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /messages -> id 629431342 (channel) and 629431346 (DM); GET /messages with channel+topic narrow returns 629431342 with its content",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "05:45",
   "cap": "cap-03",
   "capability": "Edit or delete a sent message",
   "task": "Edit message content, then delete another message",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "PATCH /messages/629431342 success; /history shows 2 versions with edited content; DELETE /messages/629431381 success, GET then returns 400 'Invalid message(s)' BAD_REQUEST",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match",
    "error_legibility": "clear"
   }
  },
  {
   "t": "06:01",
   "cap": "cap-04",
   "capability": "Move a message between channels or topics",
   "task": "Move a message to another channel and topic",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "PATCH /messages/629431400 stream_id+topic success; new narrow agentdrives-archive/'moved here' returns 629431400; old narrow returns none",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "06:01",
   "cap": "cap-05",
   "capability": "Search message history",
   "task": "Search for 'edited'",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "GET /messages narrow search:edited returns [629431342], the edited message",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "06:01",
   "cap": "cap-06",
   "capability": "Share and store files/images in conversations",
   "task": "Upload a text file and share it in a message",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /user_uploads -> /user_uploads/97069/-1saTN4ZXK6qHVb5_0os3-rl/ad-test.txt; GET /attachments lists id 11791653 ad-test.txt; message 629431428 links it; GET /api/v1/user_uploads/<path> returns a temporary URL that downloads 'AgentDrives test file' (200 text/plain)",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   },
   "notes": "Fetching the plain /user_uploads/... URL with HTTP Basic API auth returns the HTML login page (200), not the file; the documented route is the API's temporary-URL endpoint."
  },
  {
   "t": "06:28",
   "cap": "cap-07",
   "capability": "Start a voice or video call from a conversation",
   "task": "Create a BigBlueButton call link and post it in the topic",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "GET /calls/bigbluebutton/create -> join URL; message 629431464 read back with the call link",
   "notes": "POST /calls/zoom/create without a linked Zoom account: 400 'Invalid Zoom access token' INVALID_VIDEO_CALL_PROVIDER_TOKEN. Default provider is Jitsi Meet (links built client-side).",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match",
    "error_legibility": "clear"
   }
  },
  {
   "t": "06:29",
   "cap": "cap-08",
   "capability": "React to messages with emoji",
   "task": "Add thumbs_up to the first message",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /messages/629431342/reactions success; GET /messages/629431342 reactions = ['thumbs_up']",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "06:41",
   "cap": "cap-10",
   "capability": "Create a poll or collaborative to-do list in a message",
   "task": "Send /poll and /todo messages through the API",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "Messages 629431486 and 629431491; GET /messages/<id> submessages show widget_type poll (question + 2 options) and todo (2 tasks)",
   "notes": "No dedicated endpoint; the /poll and /todo message syntax (help center) is parsed server-side into widget submessages.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:12",
   "cap": "cap-11",
   "capability": "Schedule a reminder for yourself",
   "task": "POST /reminders with message_id (documented route)",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "reminder_id 134846; GET /reminders lists it with the note and message link",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:22",
   "cap": "cap-12",
   "capability": "Mark a topic as resolved",
   "task": "Rename topic 'drive log' to '✔ drive log' (change_all)",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "PATCH /messages/629431342 topic='✔ drive log' propagate_mode=change_all; GET /users/me/641750/topics -> ['✔ drive log']",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:22",
   "cap": "cap-13",
   "capability": "Save and reuse message snippets",
   "task": "Create snippet 'AD greeting'",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /saved_snippets -> 587; GET /saved_snippets lists (587,'AD greeting')",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:22",
   "cap": "cap-14",
   "capability": "Save message drafts",
   "task": "Create a channel draft",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /drafts -> ids [1989]; GET /drafts lists 'draft text'",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:22",
   "cap": "cap-15",
   "capability": "Set status, availability, and typing indicators",
   "task": "Set status 'Driving Zulip' :car: and send a typing start",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /users/me/status success; GET /users/1211474/status -> status_text 'Driving Zulip', emoji car; POST /typing op=start success",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:36",
   "cap": "cap-16",
   "capability": "Configure notification settings",
   "task": "Turn off offline email notifications, turn on channel desktop notifications, add alert word",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "PATCH /settings success; POST /register user_settings shows enable_offline_email_notifications=False, enable_stream_desktop_notifications=True; GET /users/me/alert_words -> ['agentdrives']",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "07:36",
   "cap": "cap-17",
   "capability": "Mark messages/topics/channels as read or unread",
   "task": "Mark channel read, mark one message unread then read",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /mark_stream_as_read success; POST /messages/flags remove read -> GET /messages/629431342 flags []; add read -> ['read']",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "08:21",
   "cap": "cap-20",
   "capability": "Create and manage bots for automation",
   "task": "Create a generic bot and post as it",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /bots -> user_id 1211476 + api_key; GET /users shows AgentDrives Bot is_bot true; bot posted message 629431671",
   "notes": "POST /bots response has no bot email; fetched it from GET /users/{id}. First bot call with a guessed email field gave 401 'Invalid API key' UNAUTHORIZED.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match",
    "error_legibility": "clear"
   }
  },
  {
   "t": "08:21",
   "cap": "cap-18",
   "capability": "Get read receipts for a message",
   "task": "Have the bot mark a message read and fetch receipts",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "GET /messages/629431342/read_receipts -> user_ids [1211476] after the bot removed and re-added the read flag",
   "notes": "The bot's first add of the read flag left receipts empty; after remove+add it appeared. PATCH /settings as a bot: 400 'This endpoint does not accept bot requests.'",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "08:42",
   "cap": "cap-19",
   "capability": "Connect native and custom integrations/webhooks",
   "task": "Create an incoming-webhook bot and POST a JSON event to /api/v1/external/json",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /bots bot_type=2 -> 1211477; POST /external/json -> success; GET /messages narrow agentdrives-test/webhook shows message 629431745 from 'AgentDrives Hook'",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "08:51",
   "cap": "cap-21",
   "capability": "Add custom linkifiers",
   "task": "POST /realm/filters (documented add-linkifier)",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "id 5114; GET /realm/linkifiers lists the pattern; message 'See AD-41' renders a link to https://agentdrives.com/drive/41",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "08:51",
   "cap": "cap-09",
   "capability": "Schedule a message to send later",
   "task": "Schedule a channel message 90 s ahead",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /scheduled_messages -> 134845; GET /scheduled_messages listed it with scheduled_delivery_timestamp 1791264929; after delivery it left the list and GET /messages search returned 629431742 'Scheduled by AgentDrives'",
   "notes": "Delivered within about a minute after the timestamp.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "09:08",
   "cap": "cap-22",
   "capability": "Message a channel by sending email to it",
   "task": "Get the channel's email address",
   "route": "api",
   "documented": true,
   "result": "partial",
   "verified": false,
   "evidence": "GET /streams/641750/email_address -> agentdrives-test.••••.show-sender@streams.zulipchat.com",
   "notes": "Only the address step was exercised; sending an email into the channel was not tested in this drive.",
   "quality": {
    "docs_match": "match"
   }
  },
  {
   "t": "09:08",
   "cap": "cap-23",
   "capability": "Export organization data",
   "task": "POST /export/realm export_type=2 (int, older form)",
   "route": "api",
   "documented": true,
   "result": "failed",
   "verified": true,
   "evidence": "400 'Invalid export_type' BAD_REQUEST",
   "notes": "Feature level 449 changed export_type from int to string ('public', 'full_with_consent'); the error does not list valid values.",
   "quality": {
    "error_legibility": "vague",
    "recoverable": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "09:37",
   "cap": "cap-23",
   "capability": "Export organization data",
   "task": "POST /export/realm export_type=public",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "export id 3108; GET /export/realm shows pending False with export_url; download 200 binary/octet-stream 15093",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "10:36",
   "cap": "cap-25",
   "capability": "Invite and manage users",
   "task": "Email-invite our second inbox, accept, deactivate, reactivate",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /invites (an inbox) success; GET /invites listed 1322449; mail arrived, accepted via web form headless; GET /users shows user 1211478; DELETE /users/1211478 -> is_active False; POST /users/1211478/reactivate -> is_active True. POST /invites/multiuse also returned a join link.",
   "notes": "First invite went to an inbox by a typo of ours (also our own pool address); revoked at once with DELETE /invites/1322448. POST /users: 400 'User not authorized to create users' (needs server-level permission on Zulip Cloud). Deactivating a bot needs DELETE /bots/{id}; DELETE /users/{bot_id} gives 'No such user'.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match",
    "error_legibility": "clear"
   }
  },
  {
   "t": "10:36",
   "cap": "cap-27",
   "capability": "Add guest users with limited access",
   "task": "Invite as guest (invite_as=600) and confirm role",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "GET /users/1211478 role 600 (600 = guest)",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "10:43",
   "cap": "cap-26",
   "capability": "Create and manage custom user groups",
   "task": "Create group agentdrives-testers with two members",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "POST /user_groups/create -> 400 'Available on Zulip Cloud Standard. Upgrade to access.' BAD_REQUEST",
   "quality": {
    "error_legibility": "clear"
   }
  },
  {
   "t": "10:43",
   "cap": "cap-28",
   "capability": "Set custom profile fields for users",
   "task": "Create profile field 'Drive ID'",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /realm/profile_fields -> 8593; GET /realm/profile_fields lists 'Drive ID'",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "11:12",
   "cap": "cap-30",
   "capability": "Set channel/message permissions",
   "task": "Make channel private and restrict posting to administrators",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "PATCH /streams/641750 is_private + can_send_message_group={new:1780376}; GET /streams/641750 shows invite_only True, can_send_message_group 1780376 (role:administrators)",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "11:12",
   "cap": "cap-31",
   "capability": "Set a message retention policy",
   "task": "PATCH /streams/{id} message_retention_days=30",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "400 'Available on Zulip Cloud Standard. Upgrade to access.'",
   "quality": {
    "error_legibility": "clear"
   }
  },
  {
   "t": "11:12",
   "cap": "cap-33",
   "capability": "Customize organization branding",
   "task": "Change organization description",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "PATCH /realm description -> success; POST /register realm_description = 'AgentDrives test organization'",
   "notes": "Only name/description tried; logo upload not tried.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "11:13",
   "cap": "cap-35",
   "capability": "Enable public access option",
   "task": "PATCH /realm enable_spectator_access=true",
   "route": "api",
   "documented": true,
   "result": "plan_gated",
   "verified": true,
   "evidence": "400 'Available on Zulip Cloud Standard. Upgrade to access.'",
   "notes": "The capability map lists this as free; on Zulip Cloud Free the API refuses it.",
   "quality": {
    "error_legibility": "clear"
   }
  },
  {
   "t": "11:20",
   "cap": "cap-29",
   "capability": "Configure authentication methods",
   "task": "Turn GitHub login off (and back on) via PATCH /realm authentication_methods",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "POST /register realm_authentication_methods showed GitHub enabled False after the change; Email/Google/GitLab/GitHub available on Free",
   "notes": "SAML, OpenID Connect (Plus) and AzureAD (Standard) report available False with an unavailable_reason naming the plan.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "11:40",
   "cap": "cap-37",
   "capability": "Install and use desktop, mobile, terminal, and web apps",
   "task": "Install the official zulip Python package and use its SDK and zulip-send CLI",
   "route": "sdk",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "pip install zulip (0.9.1) in a run venv; Client.send_message -> 629432100 and read back; zulip-send posted [629432104] read back via GET /messages",
   "notes": "Desktop/mobile apps not tried (no GUI in the drive).",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "12:16",
   "cap": "cap-32",
   "capability": "View organization usage/analytics statistics",
   "task": "Open /stats in the browser after logging in",
   "route": "browser",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "/stats renders 'Zulip analytics for AgentDrives Test': guests 1, file storage 22 B, charts; message counts 0 with 'Analytics are fully available 24 hours after organization creation.'",
   "notes": "No documented API for analytics; browser only. Counts lag up to 24 h for a new org."
  },
  {
   "t": "13:31",
   "cap": "pay",
   "capability": "pay step",
   "task": "Probe agent payment rails and find the purchase path",
   "route": "browser",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "No 402 anywhere: API 401 carries only 'WWW-Authenticate: Basic realm=\"zulip\"'; x402./mpp./agents.zulip.com serve the marketing page (200 HTML); no zulip entries in the x402 Bazaar or mpp.dev/api/services; OpenAPI has no billing or payment operations. /upgrade (logged in) offers Zulip Cloud Standard $8/user/month or $6.67 annual; 'Add card' opens Stripe Checkout (checkout.stripe.com, Kandra Labs, Inc.) asking for card, cardholder name and billing address, with Stripe's hCaptcha present (no visible challenge); 'or pay by invoice' also offered.",
   "notes": "Nothing paid, no card entered. Free plan needs no card. Billing address would be needed at checkout; we have none."
  },
  {
   "t": "13:31",
   "cap": "cap-36",
   "capability": "Choose and upgrade a plan",
   "task": "Reach the upgrade page and see the checkout",
   "route": "browser",
   "documented": true,
   "result": "partial",
   "verified": true,
   "evidence": "/upgrade lists Standard monthly/annual and leads to Stripe Checkout; stopped before payment (no card, no paying)."
  },
  {
   "t": "13:31",
   "cap": "cap-24",
   "capability": "Import data from Slack, Teams, Mattermost, or Rocket.Chat",
   "task": "Not attempted",
   "route": "none",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "Import is chosen at organization creation (signup form 'Import chat history?'); we have no Slack/Mattermost/Rocket.Chat export to import.",
   "notes": "Out of reach within one drive without a source workspace."
  },
  {
   "t": "13:31",
   "cap": "cap-34",
   "capability": "Set a custom domain",
   "task": "Not attempted",
   "route": "none",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "No API field for a custom domain in the OpenAPI; capability map lists it as paid; we own no domain to point at it."
  },
  {
   "t": "13:51",
   "cap": "delete",
   "capability": "delete account and data",
   "task": "POST /realm/deactivate deletion_delay_days=14",
   "route": "api",
   "documented": true,
   "result": "done",
   "verified": true,
   "evidence": "200 success; GET /users/me then 401 {'msg':'This organization has been deactivated','code':'UNAUTHORIZED'}",
   "notes": "Server allows deletion_delay_days 14..365 (POST /register server_min/max_deactivated_realm_deletion_days), so data is permanently deleted after 14 days, not at once; until then it can be reactivated by Zulip staff. Multiuse invite revoked first.",
   "quality": {
    "verify_route": "yes",
    "docs_match": "match"
   }
  },
  {
   "t": "13:51",
   "cap": "cancel",
   "capability": "cancel plan",
   "task": "No paid plan was started",
   "route": "none",
   "documented": true,
   "result": "skipped",
   "verified": false,
   "evidence": "Drive stayed on Zulip Cloud Free; nothing recurring to cancel."
  }
 ],
 "stale": false,
 "icon": "/logos/zulip.png",
 "monitored": false,
 "verdict": "Gets in on its own and does nearly all the core work: L4 · Runs on its own. Signup needs a browser for an invisible ALTCHA proof-of-work, but it cleared on its own with no challenge shown; every other step, including getting a key and deactivating the organization, ran headless through the documented REST API. Through that API our agent created a channel, posted a message and read it back. No MCP, llms.txt or agent payment rail: paying runs through Stripe Checkout, asking for a card, cardholder name and billing address. Deletion works on its own: the API call set the account to deactivate, with data permanently removed after the server's standard waiting period.",
 "page": "https://agentdrives.com/tools/zulip?via=api"
}