MCP-Tool-Referenz
Die 84 Werkzeuge, die ein Agent beim Verbinden geladen bekommt — direkt aus dem Code erzeugt. Alles Weitere ist über find_tools erreichbar.
Diese Referenz entsteht direkt aus der Tool-Registry des Produkts. Jede Zeile entspricht dem Code, nicht einer Beschreibung, die jemand nachgetragen hat.
Aufgeführt sind die Werkzeuge, die ein Agent beim Verbinden GELADEN bekommt — die Fläche für die tägliche Arbeit. Sie ist bewusst klein: was jeden Zug mitliest, kostet den Agenten Aufmerksamkeit. Alles Weitere gibt es weiterhin und ist über find_tools erreichbar, sobald es gebraucht wird.
Sie müssen nichts abtippen: ein MCP-Client fragt Namen, Beschreibung und Parameter beim Verbinden selbst ab. Diese Seite ist zum Nachlesen und für Suchmaschinen und Agenten, die vorab wissen wollen, was möglich ist.
Agents
Create/manage AI agents, agent memory and learnings, agent chains (beta)
add_workflow_step
Add a step to an existing Workflow. By default appends to the end; set insert_after to insert at a specific position (1-based, 0 = at the very front). Agent step: pass agent_id + message_template. Deterministic steps: type=http_request (url, method, headers, body_template), type=add_table_rows (table_id + rows_field/row_template — EVERY handed-over row needs a name AND a domain, or the table run drops it; add await_rows to wait for the table and get the finished rows back), type=enroll_sequence (sequence_id, channel) or type=feed_notify (message_template + optional title/action_type/lead_id_field — posts a card into the Feed).
create_agent
Create a new subagent for this workspace. The agent gets its own system prompt, model, and tool access controls.
Example: Create a ‘Lead Qualifier’ agent that only has access to research + qualification tools, with a specialized prompt for evaluating company fit.
Trigger types:
- keyword: { type: ‘keyword’, pattern: ‘qualify *’ } — invoked when message matches pattern
- event: { type: ‘event’, event: ‘lead_replied’ } — invoked on system event
- schedule: { type: ‘schedule’, cron: ‘0 9 * * 1’ } — runs on schedule
- channel: { type: ‘channel’, channel_id: ‘uuid’ } — default agent for a channel
create_workflow
Create a Workflow — the event-driven automation (per event: webhook, schedule, or manual run). Steps run in order, passing outputs forward: agent steps (bounded judgment, any connected MCP), deterministic steps (see the step type enum), and conditions. Use it for the automation AROUND Tabellen and Sequenzen — per-row work belongs in a table column, per-lead touch plans in a Sequenz. Dry-runnable via run_workflow(dry_run=true). IMPORTANT: for agent steps call list_agents first to get real agent IDs; if an agent doesn’t exist, create it with create_agent before creating the workflow.
delete_workflow
Delete a Workflow permanently (the automation itself, not one of its steps — that is delete_workflow_step). This is NOT the same as set_workflow_enabled(false): a disabled Workflow keeps its row and still shows up in list_workflows and on the trigger surface, while a deleted one is gone. Use disable when you may want it back, delete when the automation is retired. Refuses anything that is not a Workflow, and refuses an id this workspace does not own — it never reports success for a row it did not touch. Past runs in list_runs are historical records and are not removed with it.
diagnose_workflow_run
Self-debug a failed or low-quality Workflow run. Returns a structured diagnosis: which step failed, the error, the resolved prompt + actual output, and a list of suggested fixes (add retry, edit prompt, gate with a condition, swap agent). The first stop when a run “succeeded” but changed nothing, or a user asks why a Workflow failed — then apply the fix via set_workflow_step_retry / update_workflow_step / set_workflow_step_condition.
list_agents
List all agents in this workspace with their status and assigned tools. An agent IS its prompt plus its tools — there is no separate capability object to attach (Skills wurden am 27.08.2026 entfernt). Use get_agent for full details of a specific agent.
list_workflows
List the workspace’s Workflows (event-driven automations) — id, name, enabled state, trigger, and step count. The discovery entry point for the Workflow primitive: run_workflow, get_workflow_history and the step-editing tools all need an id from here.
run_workflow
Run a Workflow now. Pass optional context data that the first step receives. Set dry_run=true for a safe rehearsal — side-effect tools (message sends, campaign enrollment) no-op and return their would-be payload, so you can verify the steps before anything goes out. Set max_credits to cap what this run may spend: the run stops BEFORE the step that would exceed it, and already-completed steps stand. Same brake Tabellen-Läufe have — use it for anything that loops over rows.
set_workflow_enabled
Activate or deactivate a Workflow. When disabled, scheduled fires are skipped, event triggers do not match, and manual runs are still allowed (so users can test before re-enabling). Equivalent to the on/off switch on the Workflow detail page.
Analytics
Funnel, campaign stats, ICP performance, timelines, qualification feedback insights
get_campaign_stats
Get aggregate campaign stats (email: sent/opened/replied/bounced; LinkedIn: sent/connected/replied). Numbers come from the connected outreach providers, one call per campaign. If any campaign could not be read, the result carries partial: true, an unavailable list (sequence_id, channel, reason) and a note — READ THEM before you judge performance: a low number then means missing information, NOT low activity. Without partial the figures are complete.
get_funnel
Lead funnel as STAGES, not as a partition. replied means “reached reply or beyond” and therefore INCLUDES meeting_intent/meeting_booked/meeting_held; meetings is a SUBSET of replied. So the fields do not sum to total, and adding them double-counts meetings. Two statuses have no stage at all — interested and unsubscribed — so they appear in total and in no field (measured on one workspace: 26 leads). get_funnel.replied also differs from get_lead_counts.replied on purpose: stage vs status. For the EXACT per-status partition that reconciles, use get_lead_counts.
Blacklist
Manage domain/email blacklist entries
add_blacklist
Add entries to the blacklist. Supports single or batch add. Valid types: domain, email, company, phone, linkedin_url. To suppress a PERSON use their identity (email / phone / linkedin_url) — there is no name-based block.
list_blacklist
List blacklist entries (blocked domains, emails, companies, persons, phones, LinkedIn profile URLs). Supports filtering by type and search. Valid types: domain, email, company, person, phone, linkedin_url.
Conversations
View email/LinkedIn/WhatsApp conversation threads per lead
list_conversations
List the stored conversation ROWS of one lead across email, LinkedIn and WhatsApp — local only, no provider sync. Use it when you need the fields the narrative view drops: intent (the reply classification this workspace runs on), the conversation id (to reference or mark one row) and the raw message_content. For reading a conversation to ANSWER it, take get_lead_thread instead: it syncs from the provider first, accepts an e-mail/LinkedIn URL/name instead of only an id, and returns the messages in order with the lead beside them. Two reads, two purposes — this one is the cheaper, more literal one.
Cost Monitoring
Monitor workspace spend (LLM + external services) and get ranked cost-optimization suggestions
get_cost_summary
Get the workspace spend summary over the last N days: total USD split into LLM (ai_usage_log) and external services (service_usage_log), plus breakdowns by model, source, service, pipeline step, and day. ALSO returns balance — the workspace credit balance left (credits_remaining, plan, trial_expired). This is the number to budget max_credits against before a live paid run; a trial_expired: true blocks paid spend no matter how many credits remain. balance: null means the balance could not be read, NOT that it is zero. Note: get_enrichment_credits is a different thing — that is the prepaid balance at an email-validation PROVIDER, not this workspace’s credits. READ unpriced BEFORE quoting a total: those rows burned tokens but were stored at 0.00 USD, because that model spelling carried no price when the row was written. They count in total_tokens and contribute NOTHING to total_usd, so the spend is understated — by how much is unknown, which is why this names calls, tokens and the models responsible instead of inventing a figure. unpriced: null means every token-bearing row carried a price. Each by_source row carries BOTH avg_prompt_tokens and max_prompt_tokens (both include cache-read and cache-write tokens, which ARE the prompt). Use max_prompt_tokens to answer whether a single call ever approached the model’s context ceiling — an average cannot: one 900k-token call disappears among a hundred small ones. For an agency-managed workspace (fixed retainer, not usage-based pricing) this returns only days, balance and restricted: true instead — internal USD COGS is admin-only there (see restricted_reason).
Custom Integrations
Connect ANY third-party provider by name + API key or vendor MCP URL (no allowlist)
connect_integration
Connect ANY third-party provider to this workspace by free-form name — the first step of the external-API play. Two shapes: pass mcp_url when the vendor ships its own MCP endpoint (its tools are DISCOVERED right here and are callable immediately — the result lists them), or api_key for REST providers plus docs_url, which is what you read to wire calls yourself. Both may be given: MCP for agent work, the key for Tabellen-Spalten (column volume belongs on direct HTTP). THE ACCESS IS VERIFIED BEFORE THE SLOT EXISTS: a key the provider rejects (or a value that is plainly not a key) returns an error and creates nothing — do not retry the same value, read the reason and ask the user for the right one. Pass base_url so the check can actually run; without it the slot is created but flagged UNVERIFIED (verified: false in the result) and only proves itself on the first real run. An mcp_url that reports zero tools is treated as not connected. Idempotent per vendor name: calling again rotates the key and re-verifies. Pairs with: create_custom_tool (reference the slot via auth:{adapter_id} — never paste keys into configs), then workspace_table_add_column (per-row) or the tool_call workflow step (per-event). No allowlist exists — a vendor we have never heard of works the moment its access is stored.
list_integrations
What this workspace can reach, in two lists. CONNECTED: every provider wired up, with kind (adapter = we wrote the code and maintain it · integration = the vendor’s own API/MCP that we forward to), pays (platform_only = runs on OUR key against credits · own_key_only = the customer must bring a key, a blocking step · either = our key by default, their own optional), role, docs_url and category (crm · knowledge · email_outreach · linkedin_outreach · contact_enrichment · scraping · website_analytics · …). Read category FIRST when deciding what this workspace can actually DO: it says whether there is a CRM to derive an ICP from, a knowledge source to read positioning from, an outreach tool whose campaigns and replies describe the business. A freely connected vendor has category null — it declares none. RUNNABLE is the SECOND question and not the same one — a row is not proof: an ACCOUNT adapter needs a connected profile, so it can be connected and still runnable: false, and then the fix is „connect your LinkedIn“, never a key. runnable: null means the vendor declares no category, so there is nothing to check. What is runnable: true here is exactly what recommend_templates counts as connected — the two surfaces no longer contradict each other. ROLE answers whether a row is OURS or a vendor’s: account = a native rail of this platform, connected as an ACCOUNT — the LinkedIn, WhatsApp and E-Mail sequences run directly on it, there is nothing to buy and no vendor campaign to look for · vendor = a third-party outreach product that can drive the same channel instead of our rail · our_function = a capability we built · control/infra = everything else. Never report an account row as a vendor the customer must sign up for. AVAILABLE: what is NOT connected yet but could be, same fields — so you can RECOMMEND instead of demanding a key we already pay for. Call this FIRST when a user mentions an external tool. Metadata only, never credentials. Connections the daily health check found broken are listed on purpose with status degraded plus last_error carrying its failure class in front (e.g. [auth_failed] …) — tell the user to re-connect rather than assuming it is gone. verified: false means something different: the access was stored but never proved against the provider (usually no base_url) — it may work, it just has not been shown to. A connection with NO verified field predates the check and says nothing either way; do not report it as broken. Pairs with connect_integration (a vendor in neither list), create_custom_tool (wire a call), find_tools (a tool that may already cover the need).
Custom Tools
Create/manage workspace-specific custom tools
create_custom_tool
Create a workspace custom tool — THE way to wire a connected provider’s API (the step after connect_integration: read the provider docs, then mint the call). LAST RESORT, not the first move: a custom tool exists for a capability the platform does NOT have. Before minting one, prove it is missing — search find_tools, then read workspace_tool_describe on the closest match. A tool that rebuilds a platform capability is a duplicate with its own bugs and none of our gates; a supabase_query against a table we already expose (blacklist, leads, sequences, playbooks …) is REFUSED by name, with the native tool given. The tool becomes available to every agent in this workspace, as a Tabellen-Spalte (workspace_table_add_column) and as a Workflow tool_call step. House recipe: get_play(‘external_api_to_column’). Check list_custom_tools first to avoid duplicates; verify with test_custom_tool before wiring.
Handler types:
- http_webhook: Calls an external HTTP endpoint. Config: { url, method, headers, body_template, auth: { adapter_id, credential_key?, header?, scheme?, username?, key_position? } } — body_template may be a JSON OBJECT (preferred: {{placeholders}} in its string leaves, and a numeric leaf like timeout: 25000 stays a number) or a string — auth references the workspace credential slot (list_integrations). A pasted key is REFUSED, not discouraged: a secret in headers, in auth_header (deprecated) or in the URL query fails create/update with a named error, including a precomputed base64 of one. Read the provider docs for its auth SHAPE and pick one: scheme ‘Bearer’ (default on Authorization) · header ‘X-API-Key’ with no scheme (bare value) · scheme ‘Basic’ — we base64-encode for you, key as password with username ” by default, or key_position ‘username’. A secret in the URL/query is refused (run records keep URLs). The url may carry {{placeholders}} filled from the call: url ‘https://api.vendor.com/v1{{path}}’ with method ‘{{method}}’ makes ONE tool cover the provider’s whole API (input picks path + verb). The origin must be literal in the config — input chooses the path, never the host, because the workspace credential rides along.
- supabase_query: Reads workspace rows. Config: { table, select?, filters?, order?, limit?, single? } — ALWAYS scoped to this workspace, you never pass organization_id.
filterstakes an array of { column, op?, value_key: ‘$inputKey’ } (value comes from the call) or { column, op?, value:}; a plain object map { column: ‘$inputKey’ } also works and means op ‘eq’. opdefaults to ‘eq’; the allowed ops are eq, neq, gt, lt, gte, lte, like, ilike, in, contains — an unknown one is REFUSED by name, never silently dropped (a dropped filter returned every row, which read as “not blacklisted” for a check that never ran). Prefer a native list_* tool over querying its table by hand. - chain: Runs tools in sequence, feeding each result into the next call’s context. Config: { steps: [{ tool_name, input_map }] } —
input_mapmaps the step’s argument to ‘$contextKey’ or a literal. A step may name a CUSTOM tool of this workspace OR any PLATFORM tool (e.g. list_blacklist); custom names win on a collision. Depth is capped at 3, and a chain runs unattended, so any tool that sends or deletes is refused at the gate — put a sending automation in a Workflow, where the approval hangs on a human. - static: Returns templated response. Config: { response_template }
list_custom_tools
List the custom tools this workspace has defined (name, description, handler type, enabled). Call BEFORE create_custom_tool to avoid minting a duplicate — an existing tool that covers the need is always preferable. Pairs with: list_integrations (which provider credential slots exist to reference), test_custom_tool (run one), workspace_table_add_column (use one per row) and the tool_call workflow step (use one per event).
test_custom_tool
Run a custom tool once with sample input and see the real result — the verification step between create_custom_tool and wiring the tool into a Tabelle column or Workflow tool_call step. Executes the LIVE handler (a real HTTP call for http_webhook tools), so use a harmless sample. Also the ad-hoc way to answer a one-off question through a connected provider API without building anything permanent. Returns response_shape — a fingerprint of the response SHAPE (keys + types, never values): record it, and a later run reporting a different shape means the provider changed its answer and the tool needs re-deriving from the docs.
update_custom_tool
Repair or extend an existing custom tool — the third step of the rail, after create_custom_tool and test_custom_tool. Use it WHEN a test returns a different response_shape than before (the provider changed its answer and the call must be re-derived from the docs), when a call starts failing, or when the tool needs a new path, parameter or auth slot. Changes description, input schema, handler config, tags or enabled status; the tool keeps its name, so every Tabellen-Spalte and Workflow tool_call step that references it keeps working — building a second tool beside the broken one splits the surface instead. Verify the change with test_custom_tool before relying on it.
Deals
CRM pipeline: list/get/create/update deals and move deal stages (first-class Deal entity)
list_deals
List deals with optional pipeline/stage/status/playbook filters. Stage keys are workspace-specific — read list_deal_pipelines first to learn this workspace’s process. Returns returned (rows in this window) AND total (how many deals match these filters workspace-wide) — page with limit/offset until returned reaches total; a full page is NOT the stock.
Enrichment
Contact enrichment (email, phone), company enrichment (tech stack, signals), and email validation
enrich_contact
Find verified email and phone for one or many contacts via the connected contact-enrichment integration. Pass the contact fields directly for ONE, or contacts for a batch (max 100) — a batch runs on the background worker. Paid per lookup either way — for a whole leadlist prefer an enrichment COLUMN on the Tabelle (workspace_table_add_column kind “enrichment”, category “contact_enrichment”) so the spend is capped by max_credits and the result lands on the row.
list_company_buying_signals
Companies in this workspace that ALREADY carry a buying signal — stamped by an import source, by a signal watch, or set by hand with update_company_signals. Use it to pick who to work first: highest qualification_score on top, signals are the plain labels (the raw field keeps both stored forms: texts and {signal, weight} objects). It reads the STAMP, not the world — the standing observation is create_signal_watch, and reacting per hit is a workflow on the event company_signal_detected. For everything known about ONE company use get_company_enrichment.
validate_email
Validate one or many email addresses via the connected email-validation integration. Pass email for a single address or emails for a batch — exactly one of the two. Charged per address in both forms. Pair it with enrich_contact (validate what enrichment found before it reaches a sequence) and with get_enrichment_credits when you are about to validate a large list.
Feed
AI-prioritized recommendations, lead context, custom feed cards
get_recommendations
READ the Feed — the daily list as the human sees it. actions are resolved CARDS (title, why, lane, primary action) ranked overdue → due today → hot → rest; worklist names by id what is today, later, or an approval. worklist.today[0] IS the next best action — sorting by priority is not.
Leads
List, filter, approve, reject, bulk-manage, import leads
get_lead
Get one lead’s full record: profile, company, status, and conversation history. For the complete picture (signals, heat, enrichment, CRM stage, pinned Wissen) prefer get_lead_intelligence — this is the lighter read.
list_leads
List leads on the ENTITY SPINE (the workspace-wide lead records that sequences, replies and the CRM board share) with optional filters (status, playbook, pagination). Returns returned (rows in this window) AND total (how many leads match these filters workspace-wide) — page with limit/offset until returned reaches total; do not infer the total from a full page. Rows in a Tabelle mirror these via lead-linking — read table data with workspace_table_get; read the canonical lead state here. Looking for ONE person by name? Use search — it matches first name, last name and e-mail, and a full name like “Birol Karatas” works because every word only has to hit one of those fields. Do NOT page through the list hunting for a name: a workspace can hold thousands of leads, and “not in this window” is not “does not exist”. If search returns nothing, THEN the lead is genuinely absent.
LinkedIn search, profiles, company data, sequence management
enroll_linkedin_sequence
Enroll leads into a LinkedIn Sequenz — the gated transition from data to outreach: each lead gets its own enrollment that the stepper walks (connect → wait → message …, reply stops it). Provide manual steps or auto-generate from personalization variables. A LIVE EXTERNAL-WRITE action: sends will go out from the connected LinkedIn account — confirm with the human before enrolling, never speculatively. For bulk per-row enrollment from a Tabelle, prefer an outreach terminal column (send-gated) over looping this tool. Returns enrolled / skipped / failed: skipped means the lead was ALREADY enrolled, failed means the enrollment was refused — and errors names the reason per group with a sample lead (missing LinkedIn sender on the playbook, no playbook assigned, unsubscribed/blacklisted, invalid copy). A failure is never counted as a skip, so skipped: N genuinely means “already running”.
enroll_sequence
Enroll leads into ANY native Sequenz — LinkedIn, WhatsApp or E-Mail, and a multichannel graph that hands off between them. The gated transition from data to outreach: each lead gets ONE enrollment that the sequencer walks; a reply stops it for that lead. THERE IS NO CHANNEL ARGUMENT — the sequence’s graph decides where it starts, and the enrollment moves between channels on its own. Nothing goes out on a manual-release sequence: every enrollment is born paused and needs release_sequence_leads. Read birth in the answer — paused is the normal case there, not a failure. A LIVE EXTERNAL-WRITE action on an auto-release sequence: confirm with the human first, never enroll speculatively. Returns enrolled / skipped / failed: skipped means the lead was ALREADY enrolled (checked on the channel IDENTITY, not the lead row — the same person often exists several times), failed means refused, and errors names the reason per GROUP with a sample lead. A failure is never counted as a skip. Verify with list_enrollments; preview the copy first with preview_sequence_for_lead. For bulk per-row enrollment from a Tabelle prefer the outreach terminal column.
list_enrollments
READ the enrollments of a Sequenz or of ONE lead — the answer to “did the enrollment happen, and where does it stand?”. Per row: status (active | paused | completed | replied | failed | cancelled), current_channel (a multichannel enrollment MOVES between channels), the cursor node, when the next step is due, how many steps the graph has, and the last error. This is the read the enroll path was missing: a run that reports success proves nothing on its own. Pass exactly ONE of sequence_id or lead_id. Pure read — nothing is enrolled, nothing is sent.
Playbooks
Create, edit, clone, delete playbooks and personas; link/unlink/list a playbook’s Tabelle references (the v2 “Bausteine” reference bundle — by reference, never a copy)
create_playbook
Create a Playbook — the bracket that holds ONE go-to-market motion together: who you target (ICP, buying signals, fit criteria), what you offer, how you talk (channels, style, step counts) and which senders carry it. Sourcing and qualification read its ICP, copy generation reads its messaging fields, and every send, reply and outcome is attributed to it — so create one per distinct motion, not one per list. Born draft and INERT: nothing is sourced, nothing is sent. Wire it next — playbook_asset_pin binds the Wissen its copy renders as {{asset.*}}, playbook_table_link binds the Tabelle that feeds it rows, and set_playbook_status puts it in service (approved/active are the states the sourcing, social-scan and optimizer runs pick up). Status is a LABEL, never a send brake: the brake is the outreach_paused field on update_playbook, which also edits every field offered here.
delete_playbook
Delete a playbook AND everything that hangs off it — it removes far MORE than one row: its sequences, personas, messaging angles and pipeline config go with it. Enrollments of those sequences are NOT drained first: use empty_sequence_queue to cancel in-flight leads before deleting, or they end up orphaned. Irreversible and approval-gated. If the intent is only to STOP sending, this is the wrong tool — set outreach_paused via update_playbook (the brake), or set_playbook_status to archived (which also empties the queue). Linked Tabellen and pinned Wissen assets SURVIVE: they are referenced, not owned.
get_playbook
Get full playbook details including all fields, personas, and sequences. Enthält url — die direkt öffnenbare Adresse dieses Playbooks in der Oberfläche. Sie ist im selben Workspace teilbar (Login + Mitgliedschaft nötig, kein öffentlicher Link). Wer nach „Link”, „URL” oder „teilen” gefragt wird, gibt dieses Feld heraus statt zu behaupten, es gebe keins.
list_playbooks
Listet die Playbooks des Workspace mit beiden Achsen plus seinen BAUSTEINEN. bausteine zählt, was das Playbook referenziert — gepinnte Wissen-Assets, verknüpfte Tabellen, Sequenzen; ein Playbook IST ein Bündel von Referenzen, und alle drei bei 0 heisst: leeres Bündel. lifecycle (draft · live · archived) sagt, wo im Leben das Playbook steht, sending (sending · paused · idle) sagt, ob es sendet. Die Achsen sind getrennt, weil der Status entscheidet, ob Crons das Playbook anfassen, während outreach_paused die einzige Bremse am Versand selbst ist — ein Playbook kann im Dienst sein UND pausiert. „live” umfasst approved UND active: für jeden Läufer bedeuten die beiden dasselbe. Für die volle Konfiguration get_playbook — die ICP-Listen sind hier auf die ersten 10 Einträge gekappt (mit sichtbarem Rest-Hinweis), damit die Zeilen samt url nicht hinter einer Kürzung verschwinden. Jede Zeile trägt url — die direkt öffnenbare, im Workspace teilbare Adresse des Playbooks.
playbook_table_link
Verknüpft eine Tabelle (workspace_table) mit einem Playbook — als Referenz, nie als Kopie. Das Playbook-Bundle („Bausteine”) referenziert damit das Tabellen-Segment; die Tabelle selbst bleibt unverändert und kann von mehreren Playbooks referenziert werden. Optionales label benennt die Rolle der Referenz (z. B. „Sourcing”). Pro (Playbook, Tabelle) gibt es genau eine Verknüpfung — erneutes Verknüpfen aktualisiert das Label. Ist Playbook oder Tabelle unbekannt (oder die Tabelle gelöscht), wird nichts geschrieben und eine klare Fehlermeldung zurückgegeben.
set_playbook_status
Setzt das Status-ETIKETT eines Playbooks. Jeder Wert ist von jedem aus setzbar — es gibt keine Übergangs-Regeln (auch approved → draft geht, um eine Freigabe zurückzuholen). WICHTIG: der Status STARTET UND STOPPT KEINEN VERSAND. Was ein Lead bekommt, entscheiden die Enrollments der verbundenen Sequenz; die Bremse am Versand ist outreach_paused (Feld an update_playbook). Der Status steuert die vorgelagerten Läufe: approved/active gelten als IM DIENST (Sourcing, Social-Scan, Health, Optimizer fassen das Playbook an), draft/pending_approval/paused nicht. archived ist die Ausnahme: Archivieren stoppt den Versand ausdrücklich UND leert die Warteschlange. Zum Entfernen delete_playbook.
Postfach
The real mailbox: read the inbox, threads, folders — including mail from people who are NOT leads — and write DRAFT answers into it. Never sends; the human sends from the mailbox.
mailbox_list
READ the workspace mailbox — the real inbox, including everything from people who are NOT leads (customers, applicants, suppliers, an accountant). Use it to triage the day, to find what needs an answer, or whenever a human says “check my mail” / “what came in?”. Returns one line per message without the body; follow up with mailbox_thread for the wording. Defaults to the inbox — pass role:“sent” for what the workspace sent, role:“drafts” for answers waiting to go out. Pairs with mailbox_thread (read one conversation) and mailbox_draft_reply (answer it). For the history with a known LEAD across channels, get_lead_thread is the better tool. FILTERS make this the search: person: everything exchanged with one address in either direction, from: only what that address sent, after:/before: a date window. Without a filter you get the folder, with one you get the answer to “what did we agree with them?” — participants and dates are searched, NOT full text. (Until 2026-08-22 this was a second tool, mailbox_search, whose own error message read “sonst ist es mailbox_list”.) body:true returns each message’s FULL text instead of the preview — for automation that has to judge the CONTENT (score an application, classify an invoice), and for a table column, which cannot fetch per message afterwards. Pair it with a filter or a small limit; without one you pull whole bodies you did not ask for.
mailbox_thread
READ one mailbox conversation in full — every message both directions, oldest first, with the actual wording and quoted history stripped. Use it BEFORE answering anything: it is the only way to see what was already promised. Take the thread_id from mailbox_list. Pairs with mailbox_draft_reply, which derives recipients and subject from this same thread.
Research
Research companies, qualify against ICP, find leads
find_leads_at_company
Find decision-makers at a company by role/title. Returns name, title, LinkedIn URL.
Runs
One monitoring read over every execution — table Abläufe, Workflow runs, sourcing runs (the Run primitive)
list_runs
ONE monitoring read for every execution in the workspace — table Abläufe (column runs, imports, source fills), Workflow runs, sourcing runs, queued/running background JOBS, and TRIGGER firings (an event trigger that invokes an agent does real, billable work but writes no workflow_run) — merged onto one row shape: source, title (never a raw id), kind, status, item counts, credits_used, error, timestamps, dry_run flag. The entry point for “what is running / what just happened / what failed?” across all four engines; drill into a specific run with the engine’s own tools (workspace_table_run_health, diagnose_workflow_run, check_sourcing_progress, get_job_status). Filter by status — the values a row actually carries are running | completed | failed | cancelled | pending; common spellings (succeeded, success, done, queued …) are normalised to those, and an unknown one is rejected by name instead of quietly matching nothing. Filter by source (table | workflow | sourcing | job | trigger | webhook), and limit (default 50, max 200). For source=trigger the kind is the event name (linkedin_replied, email_replied …) and there is no href — a single-agent trigger has no page of its own. For source=webhook the row is ONE inbound event a connected provider delivered, from the durable webhook ledger: kind names the event, status says whether its handler settled, attempts counts replays. Pair it with get_lead_thread when an expected reply never showed up — a failed or long-running webhook row is where an inbound reply got lost.
Sales Blueprint Brain
Manage the workspace Sales Blueprint Brain — knowledge base and feedback
get_blueprint
Returns the workspace Sales Blueprint Brain — full or specific sections. Use this to read the current ICP, copy patterns, personas, objection playbook, and other strategic knowledge.
Senders
Manage email and LinkedIn sender accounts, LinkedIn pool health and warmup
create_sender
Create or update a sender (one person with their contact data, signature, and linked channel accounts). Idempotent by email — calling this twice with the same email updates the existing row instead of creating a duplicate. Pass only the fields you have; account IDs are optional and can be linked later via update_sender. Use list_available_accounts first to get valid account_id values.
list_senders
List all senders (persons with linked email/LinkedIn/WhatsApp accounts) for the workspace.
Sequences
Create, edit, clone multi-channel outreach sequences
create_sequence
Create a Sequenz — the per-lead touch plan on ONE channel (email, linkedin, or whatsapp): ordered steps with delays and copy, walked per enrolled lead over time. Starts as status draft with linear steps and runs its branching NATIVELY from the start (graph_mode on) — add conditions later with update_sequence({graph}) and they execute, no switch to flip. Optionally bind trigger signal types so a detected buying signal routes leads in deterministically. Nothing sends on create — sends start when leads are ENROLLED (enroll_linkedin_sequence, or an outreach terminal column on a Tabelle). ONE sequence per playbook AND channel: if that pair already exists the call is REFUSED, and the way forward is update_sequence on the existing one (list_sequences shows which pairs are taken). Measured 22.08.2026: that single rule caused 14 of ~20 failures on this tool — the agent tried to create a second LinkedIn sequence for a playbook that already had one.
delete_sequence
Delete a sequence template. Empties its queue first (cancels in-flight enrollments referencing it); enrollment history survives. A sequence linked to an external campaign needs force=true — the external tool campaign is NOT stopped automatically.
get_sequence
Get sequence details and locked status. Pass simulate to also get a DRY-RUN timeline — the projected touches (node, channel, day-offset) a lead in that hypothetical state would experience. Pure projection: nothing is enrolled or sent.
list_sequences
List the workspace’s Sequenzen (the per-lead touch plans) — id, name, channel, status, step count, whether it runs the branching graph natively (graph_mode), whether it is locked to an external campaign, and its trigger-signal bindings. The discovery entry point for the Sequenz primitive: every other sequence tool needs an id, and ids are not guessable. Filter by playbook or channel to narrow.
preview_sequence_for_lead
Show the FINISHED message text a specific lead would receive from a sequence — before anything is sent. Renders every step through the SAME resolver and the same unresolved-slot brake the send path uses (lead + company fields, personalization_variables, {{asset.}} pinned Wissen, {{cell.}} from the lead’s linked table row), so its verdict is binding: a step reported would_send:false PARKS at send time instead of going out. Use it before releasing a sequence, and whenever copy references table columns — an unresolved placeholder is visible here instead of at the recipient. Pure read: nothing is enrolled, nothing is sent. Pairs with update_sequence (fix the copy) and release_sequence_leads.
update_sequence
Change an existing Sequenz in place. It does NOT rename — there is no name field here. Linear steps and the branching graph are two representations of the same touch plan: set graph to author a BRANCHING sequence, omit it to keep linear steps. Cannot edit steps/graph if the sequence is locked (linked to a campaign); bindings stay editable. graph_mode=true makes NEW enrollments execute the graph natively — multichannel: LinkedIn, WhatsApp and email nodes hand off between steppers (email sends from the workspace’s connected mailbox with a hard daily cap; without one the email node parks with an honest reason). In-flight enrollments keep their snapshot; without graph_mode a stored graph is authoring/preview only and the linear stepper keeps running.
Signal-Watches
Standing company watches: diff pages on a schedule, stamp buying signals, fire company_signal_detected per hit
create_signal_watch
Standing watch on a list that already exists: on a schedule it re-reads the page in url_field per row of a company-bound Tabelle, diffs it block-by-block, and when a NEW block contains one of match it stamps signal_name onto the company (buying_signals_detected) and fires company_signal_detected { signal, company_id, domain, evidence }. It never creates rows; the hit goes onto the matched row: signal, signal_grund (the new block) and signal_am, auto-created on first hit, readable as {{cell.signal_grund}} in copy columns (latest hit wins; the history is the event stream). Pair it with create_workflow (trigger event company_signal_detected, filters { signal: 'run_signal_watch to see it work instead of waiting a day for the second tick. To PULL companies IN, use workspace_table_add_source instead.
Sourcing
Source companies from Google Maps, LinkedIn, post engagement, custom data sources
find_companies
Der Job „hol mir Firmen“: fills a company Tabelle with real rows from every source this workspace can run — free sources BEFORE paid ones, each source topping up what the previous ones did not deliver (a sourcing waterfall collects a SET; it is not first-hit-wins). Target: into_table (name or id of a company-bound Tabelle) OR playbook_id (uses the table linked to that playbook) — exactly one. Without either it falls back to the LOOK-ONLY mode: it asks the connected research providers for matching company names and returns them as UNVERIFIED suggestions ({companies, count}) — no rows, no provenance, no cost record. Sources come from the ONE catalog (workspace_capabilities → sources); pass sources to pick them, otherwise the workspace’s runnable, ICP-servable modules are planned automatically. A plan containing ANY paid source REQUIRES a positive max_credits — the cap covers the whole plan. Returns the enqueued job id (+ the ordered plan); rows appear via workspace_table_get, progress via list_runs. For a source that needs its own inputs (a scraper actor, a LinkedIn post) use workspace_table_add_source; for a recurring source workspace_table_schedule_source.
System Overview
Explain the platform model — primitives, object model, governance — to an agent orienting itself (explain_system), plus the setup+debug contract for Workflows/Sequenzen/Tabellen: which tool writes which config field, what the runtime actually executes, and what dry_run really simulates (automation_capabilities)
get_play
Get the HOUSE BUILD ORDER for a standard GTM motion — the ordered steps, which tools to call at each step, WHY each step sits where it does, and the guardrails. Use it BEFORE building when a request matches a known motion, instead of deriving an order from tool names: “source leads, qualify them and build a LinkedIn sequence” → lead_list_to_outreach; “every day new matching companies” → recurring_source; “enrich this list I already have” → enrich_existing_list; “when X happens, do Y” → event_to_action. Call with no id to list the available plays. Getting the ORDER wrong is the expensive mistake here — running a column before its source filled the rows, or paying to enrich rows that qualification was about to discard.
Templates
Every template in one list — platform-shipped and workspace-saved, across agents, workflows, tables and playbooks; install one, save an existing object as your own template, rename it, delete it
apply_template
Install ONE template from list_templates into this workspace. A BUILDING BLOCK template (agent, table, workflow, sequence) creates exactly one object of its noun. The BUNDLE (playbook) creates the whole recipe in one call — personas and messaging angles as Wissen, the shipped sequences, the Ablauf table from its step plan — and binds each of them to the playbook. What it does NOT do today: connect the table to the sequence. The Ablauf table of a shipped template is company-bound and therefore has no enroll column, so enrolling stays a manual step. Check bringt_mit in list_templates first: a bundle whose list is empty brings no building blocks at all. This is the ONE way to apply an AGENT template, and the general way for the rest; the per-kind tools (install_workflow_template, create_playbook_from_template, workspace_table_from_template) are still there and take OPTIONS this tool does not (force, relation_table_map, source_max_credits, entity_binding, language, create_table) — reach for them when you need one of those. Installing twice is an ANSWER, not an error: kinds with arity “einmal” (agent, workflow) return the existing object with reused: true instead of failing. The result names what did NOT arrive — droppedReferences (a reference that could not be resolved; supply it and re-apply) and skipped (something the template cannot carry; needs to be built by hand). Nothing runs and nothing costs credits on install: the object arrives INERT. Pair with list_templates before, and workspace_table_preflight after.
recommend_templates
Which proven plays can ACTUALLY run in this workspace right now — the first call after signup, before building anything. Reads what is connected and holds it against what each template needs (derived from its own columns and steps, so it cannot drift), then answers in three buckets: gangbar (everything it needs is connected — richest first, so the play that gets the most out of what you already have comes top), braucht_noch (the missing capability CATEGORY by name — connect that and it moves up; nearest first) and nicht_beurteilbar (the need could not be derived — never guessed). Requirements are CATEGORIES and never vendor names (linkedin_outreach, email_outreach, crm). Covers the PLAYS — the table building block and the playbook BUNDLE (the whole recipe: several blocks plus the links between them, see list_templates); agent and workflow templates name tools rather than providers, so there is nothing to judge, and find_tools reaches the plain catalogue for those. Pair with list_integrations (what is connected and what could be), apply_template (install one) and workspace_table_preflight (what is still missing AFTER installing).
Triggers
Event-driven automation triggers (events, schedules, keywords, thresholds)
create_trigger
Create a new automation trigger. Types:
- event: fires on system events (lead_replied, meeting_booked, etc.)
- schedule: fires on cron schedule — config.cron, 5 fields, from , a number, a range (1-5), a list (1,3,5) or a step (/15). Names like MON-FRI are NOT read; write 1-5. An expression outside those forms is refused here instead of becoming a trigger that never fires.
- keyword: fires when keyword detected in message
- threshold: fires when metric crosses threshold
- pipeline: fires at pipeline step completion
Website Scraper
Read a public page cheaply (self-hosted scraper, optional JSON extraction) and scrape company websites for leads
read_page
Read a public web page CHEAPLY: fetches it via the self-hosted scraper and returns its text — no model involved, no research agent. Pass extract to have a cheap model format the page into JSON (add schema to fix the shape). Use this for career pages, pricing pages, imprints, product pages — anything public you want to read or turn into fields. Pairs with a workflow tool_call step or an ai column. Prefer this over research tools when you already KNOW the URL; use the research tools when you still have to FIND the information.
Wissen
Operate Wissen assets (the workspace’s reusable, immutably-versioned knowledge: ICP, Persona, Offer, Positioning, Messaging Angle, Proof): list (optionally filtered by kind/status, e.g. status=proposed for pending proposals), read an asset with its current revision + history, create, revise (append revision), roll back the current-revision pointer, approve/reject a proposed asset, archive
playbook_asset_pin
Bindet ein Wissen-Asset an einen Playbook-Slot (per Referenz; optional auf eine Revision fixiert). slot ist die Rolle und muss zur Asset-Art passen (icp, persona, offer, positioning, messaging_angle, proof, signal, lead_magnet) — ein ICP-Slot nimmt nur ein icp-Asset. learning ist KEIN Slot: Learnings sind Vorschläge, die über eine Freigabe zu Asset-Revisionen werden. Ohne pinned_revision_number folgt die Bindung der jeweils aktuellen Revision des Assets (Verbesserungen wirken automatisch); mit pinned_revision_number wird sie auf genau diese Revision fixiert (reproduzierbar). Pro (Playbook, Slot) gibt es genau eine Bindung — erneutes Binden ersetzt die vorige. Passt die Art nicht zum Slot oder ist Asset/Revision/Playbook unbekannt, wird nichts geschrieben und eine klare Fehlermeldung zurückgegeben.
playbook_assets_list
Listet die Wissen-Asset-Bindungen eines Playbooks — je Slot das gebundene Asset (id, kind, name), die wirksame Revisionsnummer (die fixierte, sonst die aktuelle) und ob die Bindung fixiert ist (pinned) oder der aktuellen Revision folgt.
wissen_asset_create
Hält Wissen fest — EIN Werkzeug für beides: OHNE asset_id entsteht ein neues Asset (Revision 1), MIT asset_id eine neue FASSUNG des bestehenden Assets. Fassungen sind unveränderlich — eine neue überschreibt nie eine bestehende und ist standardmäßig nur ein VORSCHLAG: das Asset zeigt weiter auf die bisherige Version, {{asset.*}} löst also NICHT auf die neue auf, bis sie über activate: true oder wissen_asset_set_revision aktiv wird. Der Inhalt wird fail-closed validiert — ein unbekanntes Feld oder ein fehlendes Pflichtfeld wird benannt abgelehnt, ohne dass etwas geschrieben wird. Verweise auf andere Assets (z. B. icp_refs/offer_refs eines signal-Assets) sind Asset-Ids und werden ebenso geprüft: Existenz, richtige Art, gleicher Workspace.
wissen_asset_get
Liest ein Wissen-Asset: seinen aktuellen Revisionsinhalt (typisierter Body je nach kind) plus die Revisions-Historie (Metadaten je Revision — Nummer, note, actor, Datum). Über die Historie erkennst du, welche Version aktuell aktiv ist und worauf du mit wissen_asset_set_revision zurücksetzen kannst.
wissen_asset_list
Listet die Wissen-Assets dieses Workspace — die wiederverwendbare, versionierte Wissensbasis (ICP, Persona, Offer, Positioning, Messaging Angle, Proof, Signal). Nur Metadaten pro Asset (id, kind, name, status, aktuelle Revisionsnummer, updated_at) — die Inhalte einer Revision holst du über wissen_asset_get. Optionaler kind-Filter grenzt auf eine Asset-Art ein; optionaler status-Filter grenzt auf active/archived/proposed ein — status=proposed findet die vom System vorgeschlagenen Assets (z. B. destillierte Learnings), die noch auf eine Entscheidung per wissen_asset_set_status warten.
Workspace
Workspace settings, credentials, memory (facts, preferences, instructions), reporting a product bug or feature request
assign_playbook_senders
Weist einem Playbook seine ABSENDER zu — das Feld sender_ids, das der Versand wirklich liest. Nimm dieses Werkzeug, wenn ein Lauf oder eine Sequenz mit no_sender_assigned stehen bleibt: LinkedIn und WhatsApp lösen ihr Konto über playbooks.sender_ids → senders.{linkedin,whatsapp}_account_id auf, und ein leeres Array heisst „kein Absender”, egal was sonst am Playbook steht. ACHTUNG: die Felder email_sender_id/linkedin_sender_id/whatsapp_sender_id an update_playbook sind NICHT dasselbe — sie werden auf diesem Pfad nicht gelesen. Die Liste ERSETZT die bisherige Zuweisung (kein Anhängen); list_senders und list_available_accounts liefern die gültigen ids. Ein Absender aus einem anderen Workspace wird abgelehnt, bevor etwas geschrieben wird.
get_setup_status
Snapshot of this workspace’s campaign-setup readiness: channel connections (email/LinkedIn/WhatsApp), senders, playbooks, and required integrations. Returns a list of concrete next_steps the agent can act on. Call this FIRST when a user asks to set up or launch a campaign — it prevents guessing and avoids skipping prerequisites. Refresh it between major actions (e.g. after connecting an account).
report_issue
File a bug report or feature request about the GTM Automation product itself — use when the user in this conversation says something is broken or asks for something the product doesn’t do yet. NOT for workspace data issues (a bad lead, a stuck sequence) — those go through the normal workspace tools. Lands in the same queue as the in-app “Fehler melden” dialog: a bug gets a fix-it-yourself pipeline, a feature request gets a GitHub issue filed for the owner to triage.
save_memory
Schreibt eine Workspace-Notiz (Fakt, Präferenz, Anweisung, Kontakt, Kontext über die Organisation) — anlegen UND ändern in einem Verb. OHNE memory_id wird eine neue Notiz angelegt; dafür sind category und content nötig. MIT memory_id wird genau diese Notiz überschrieben; dann genügt das Feld, das sich ändert. Bestehende Notizen findest du über list_memories, entfernen über delete_memory.
workspace_object_describe
DIE ANLEITUNG zur Objekt-Fläche: ohne kind alle Objektarten mit einer Zeile; mit kind die Felder für create und update (samt Pflichtfeldern und erlaubten Werten), die Filter für list, die Wirkung je Verb und die Felder, die nur ein benanntes Werkzeug schreiben darf. Reine Lesung, kostet nichts — rufe es vor create/update, statt Felder zu raten.
Workspace Tables
Operate Tabellen (workspace database tables): discover every creatable capability (workspace_capabilities), read the relational schema (tables + columns + relation edges), list, create a table, soft-delete a whole table, add a column (incl. relation), update a column (name/run_condition/config), soft-delete a column, read rows, add a row, edit a manual/relation cell, soft-delete a row, trigger a column run, import a playbook’s companies/leads as entity-bound rows, build/refresh the “Positive Leads” list (sync_positive_leads — every positively-replied lead as a pure entity-bound view), fill/schedule company-row SOURCES (add_source / schedule_source / list_sources / delete_source), check a table BEFORE running it (preflight — graph defects, cost of a full pass, resolved sample inputs), and save a table as a reusable workflow template + recreate a table from one (structure-only, validated)
workspace_capabilities
Discover EVERYTHING this workspace can do — the live, data-driven catalog of creatable capabilities, so you never have to guess what modules exist. Returns two blocks: columns (the add-column catalog grouped by ORIGIN — grundlagen = what the table itself does (manual/formula/AI/relation), unsere_tools = built and maintained by us (no key, runs on credits), verbundene_anbieter = the third-party providers THIS workspace connected, called directly against their API. Each item carries id, label, column_kind, category, cost_per_row, connected, selectable, backed_by (which connected provider actually answers a category module — otherwise you would be guessing), and the create_tool that creates it, e.g. workspace_table_add_column with create_kind) and sources (the company-row import sources — pool, scraping, lead database, Indeed jobs, generic scraper actor, LinkedIn post-engagers, job-change, lookalike, social listening, webhook — each with connected/suggested/paid flags and the create_tool that creates it, e.g. workspace_table_add_source or workspace_table_schedule_source). A source that needs nothing to be wired (pool, lookalike, webhook) always reports connected: true; a source that needs a provider and has none reports connected: false PLUS requires, naming the missing connection category (e.g. ‘linkedin_data’) — so a source you cannot run yet is never mistaken for a broken one. Org-scoped; reflects THIS workspace’s connected integrations. Use it to find a module’s id + the exact tool to call before creating a column or source.
workspace_schema_get
Read the workspace’s relational data model AND its Wissen assets: tables, columns, relation edges, and the reusable knowledge (ICP/Persona/Offer/Positioning/Messaging Angle/Proof) — call this to understand the workspace before operating on it. Returns every Tabelle (id, name, entity_binding, description) with its columns (key, name, kind, data_type); a ‘relation’ column additionally carries its RESOLVED edge (target_table_id, target_table_name, display_column), so the tables response is a graph — tables are nodes, relation columns are directed edges. Also returns assets — every Wissen asset at list level (id, kind, name, status, current_revision_number); fetch a typed content body via wissen_asset_get. Also returns handoffs — the workspace PROCESS GRAPH: nodes (Playbooks, Wissen assets, Tabellen, Sequenzen, Workflows, Absender, signal/feed/external endpoints, each with status) and edges, the CONFIGURED wiring between them. Read it to see the whole motion at once. Plus two defect lists: dangling (handoffs whose target is missing or archived — dead config that looks alive) and issues, each with a stable code, severity (error = the process does not run there; warning = it runs worse), the node it hangs on, and a hint with the next step. The expensive class is the MISSING edge, not the dead one — a sequence nobody enrolls into, a channel with no Absender, a table with no Playbook ({{asset.*}} resolves empty). Work issues before building anything new, and call this again after wiring: an edge you invented shows up as an issue, not as a finished motion. handoffs.legend is the RULE beside that state — every handoff that CAN exist, through which mechanism and tools, and legend.myths, the ones that do NOT (a Sequenz never writes back into a Tabelle; a Playbook starts nothing) with the path to take instead. Read the legend BEFORE wiring: an invented edge is configured, looks finished, and never fires. Also returns column_arg_contracts — per enrichment category the declared args_template fields (key, label, hint, required); read them instead of guessing parameter names (a custom_tool column’s fields live in its own input_schema via list_custom_tools). Org-scoped. Optional table narrows the tables to one; relation edges still resolve names workspace-wide, and assets always covers the whole workspace.
workspace_table_add_column
Add a column to a Tabelle, or edit one that is already there — ONE call, so an agent need not decide before it knows whether the column exists. Without column a NEW column is appended (position = max + 1); with column (its key or id) THAT column is edited. table takes a name or id. Creating requires name + data_type and is the only moment kind and the column key can be set; editing takes any subset of name/data_type/run_condition/on_error/config and refuses an empty patch rather than reporting a no-op. config is SET when creating and MERGED onto the stored config when editing — an edit can overwrite a config field but never remove one. The contract field role is fixed once the column exists and rejects a change (create a new column instead); output_schema stays editable and is hard-validated on every patch. Pair with workspace_table_run_column (mode ‘dry_run’ first — a live ‘ai’/‘enrichment’ run spends Credits once per successful cell and requires max_credits), workspace_table_preflight before the first real run, and workspace_table_delete_column to remove a column.
workspace_table_add_row
Add one row to a Tabelle (workspace database table). values maps column key -> value; every key must already exist as a column on the table (create columns via the UI first) — an unknown key is rejected with the list of valid keys. Auf einer GEBUNDENEN Tabelle kann entity_id die Zeile direkt an ihren Lead bzw. ihre Firma hängen. Bei firmen-gebundenen Tabellen wird die Firma sonst aus der Domain-Zelle aufgelöst; bei LEAD-gebundenen gibt es nichts zu raten — ohne entity_id bleibt die Zeile eine Waise, und jede entitätsbezogene Spalte liest ins Leere. Nachträglich binden: workspace_table_bind_row.
workspace_table_add_source
Fill a Tabelle NOW from a data source (one-shot company-row import) — the agent parity for ‘Firmen hinzufügen → Quelle’. table accepts a name or id. Pick a source module id (discover them via workspace_capabilities): ‘pool’ (free), ‘lookalike’ (free own-data), ‘scraping’ (Maps, paid), ‘lead_sourcing’ (lead database, paid), ‘indeed_jobs’ (hiring signal, paid), ‘generic_actor’ (any catalog scraper actor — needs actor_id + field_mapping{name:…}, paid), ‘post_engagers’ (LinkedIn post → engager companies, uses your LinkedIn). query/location/max_results feed the search. For source: 'pool' ALSO pass industry/company_size_min/company_size_max/country (ISO-2) when the ask names them — query alone is loose text similarity and matches on the company NAME (a car dealer named ‘B2b Handel’ matches a ‘B2B SaaS’ query), not on size or industry. A PAID source REQUIRES a positive max_credits (money-audit). Returns the enqueued job id — the fill runs in the background (watch rows with workspace_table_get). For a RECURRING source, use workspace_table_schedule_source instead; ‘job_change’ is schedule-only.
workspace_table_create
Create a new Tabelle (workspace database table) with its initial columns — the build step before anything runs. Column positions follow array order (first column = position 0) and table names must be unique per workspace. Each column takes the same key/name/kind/data_type/config payload as workspace_table_add_column, which is also how you extend or edit the table afterwards. Running an ‘ai’/‘enrichment’ column later spends Credits once per successful cell — preview with workspace_table_run_column mode ‘dry_run’, live runs require max_credits. Pair with workspace_table_add_source (where the rows come from) and workspace_table_preflight (what is still missing before it runs daily).
workspace_table_delete
SOFT-delete a whole Tabelle. The table stops existing in the list, schema, and grid, its in-progress runs are stopped, and its columns + rows are archived along with it — but the delete is REVERSIBLE by an operator (nothing is hard-dropped; cells are left untouched). REFUSED if another Tabelle still references this one via a relation column — remove those relation columns first. table accepts a name or id. Since a deleted table no longer resolves by name/id, calling this again on an already-deleted table returns a clean ‘not found’ rather than an error about the delete itself.
workspace_table_get
Read a Tabelle (workspace database table): its columns and a page of rows. table accepts name or id. Each column carries its category when it has one — kind only says THAT a column enriches, category says WHICH module runs (company_research vs contact_enrichment vs find_leads). FIND instead of paging: lead_id/company_id returns that entity’s row directly (rows carry entity_id, so you can go person → row and back), where filters on any column (AND-combined; an unknown column is a named error, never an empty result), and select returns only the columns you name — a full read of a wide table can otherwise exceed an agent’s context on 50 rows. Paginated: limit defaults to 50, capped at 200; offset for further pages. CONNECTED DATA: include: ['entity'] hydrates each row with its linked lead/company record (name, email, domain … — the same mirror the UI shows), include: ['relations'] resolves every relation cell from the raw target-row UUID to { row_id, table, display } so a reference reads as data instead of an id. include: ['mappe'] returns the WORKBOOK this table sits in — every table of the same Mappe and the configured handoffs between them (create_lead / relation), the same graph the UI’s Mappe lens draws. Read it before wiring a second table: it shows which tables already belong together and where a handoff points nowhere. All are off by default (a wide table + hydration is a lot of context) — ask for what you need.
workspace_table_list_sources
Everything that feeds a Tabelle, in two families. sources = the SCHEDULED sources (workspace_table_sources) — id, launch, category, config, cadence, max_credits, max_results, label, last_run_at; use the ids (and the stored config as the edit base) with workspace_table_schedule_source (update) or workspace_table_delete_source. inflows = what feeds it from ELSEWHERE and is therefore NOT in that list: webhooks (a push ingest URL bound to this table — id/slug/enabled/ingest_url; the secret is shown only at creation and never here), upstream_tables (a create_lead column on ANOTHER table that inserts rows here — change it THERE), workflows (an add_table_rows step). An empty sources does NOT mean nothing feeds the table — read inflows before concluding that. table accepts a name or id.
workspace_table_preflight
ABNAHME a Tabelle BEFORE you run it — free, read-only, no cells written, no provider or model called. Call this after building/changing a table’s columns and before the first paid run, and again whenever a daily run silently loses rows. Returns (a) findings: rule-based defects on the column GRAPH that no per-column validator can see — a gate pointing at a renamed column (falls closed for EVERY row, no error), a template ref that resolves to nothing, a research column missing its output_schema (the provider rejects the whole batch), auto_run columns on a table whose auto_advance is off (the Ablauf never starts by itself), the exact column where the Ablauf stops; (b) columns: per column the rows that actually pass the gate, the credits a full pass costs, and the RESOLVED inputs for the first 3 rows (so an empty variable is visible before it is paid for); (c) total_credits plus, when you pass max_credits, whether that cap covers a full pass — the number that prevents a run from being cut off mid-way. verdict is advisory: ‘blocker’ means a total loss is PROVEN for that finding, never ‘you may not build this’. Findings are rules, not a whitelist — a novel column combination simply produces no finding. Declare expect (what you are building: fills_itself / runs_daily / enrolls_leads) and this becomes the DONE-check for an iterative build: fix what it names, call again, and you are finished when findings is empty. Without expect nothing is required of the table — a plain data list is not a defect. With expect: ['complete_data'] the answer also carries gaps: rows filled vs empty per column, biggest hole first — the number that makes “gapless data” checkable and a targeted backfill possible (a second column gated is_empty on the first hits exactly the empty rows). Pair with workspace_table_run_health (what a PAST run lost) and workspace_table_run_column mode ‘dry_run’ (one column in depth).
workspace_table_run_column
Run a column on a Tabelle (workspace database table) — (re)computes a formula/ai/tool/enrichment column across all rows, or a subset via row_ids. ONE CALL FOR THE WHOLE COLUMN — do NOT loop over small row batches. Each call becomes ONE background job, and a job’s cells run in parallel (32 at a time by default): 5.000 cells in one call finish in ~9 minutes. Split into calls of 2-10 rows, the same work becomes hundreds of jobs the worker takes a handful at a time (measured in production: 249 such jobs for 1.511 rows starved the queue for over an hour). Omit row_ids for the whole column; use it only for a genuine subset, never for chunking. RECOMMENDED FLOW for paid columns (ai/enrichment): call with mode ‘dry_run’ first — free and side-effect-free, returns {rows, estimated_credits, sample_inputs} so the spend is known before it happens; then run live with max_credits set. A LIVE run of a paid column REQUIRES max_credits (> 0, hard cap): once the run’s credit tally would exceed it, remaining cells are skipped with reason ‘max_credits_reached’ and the run completes partially. A cap that covers the work (rows × per-cell estimate) keeps the run parallel; a TIGHT cap makes it serial — a hard cap is only exact when each cell’s real spend is known before the next starts. FASTEST PATH for a big backlog: max_cells — YOU set how many cells this call may run, and it takes only cells that are not already succeeded. That bound replaces the credit cap (no max_credits needed), so the run stays PARALLEL, and it never re-charges a cell that is already paid for. Use it instead of a tight max_credits, which serialises the run to one cell at a time. Live runs are asynchronous (background job, returns the job id — poll with workspace_table_get); dry_run answers immediately. No automatic retries.
workspace_table_run_health
Report a Tabelle’s per-column RUN HEALTH — for each column: total cells, succeeded / failed / skipped / pending / running counts, and the distinct provider error (or skip) messages ranked by frequency. This is the debugging read: it surfaces WHICH column is failing and WHY (e.g. a solar column skipping ‘no_coordinates’, an enrichment column erroring ‘rate limited’), so you can fix the column config. Optionally narrow to one column (key). Columns are returned most-broken first. truncated is true if the issue-cell sample cap was hit.
workspace_table_schedule_source
Create OR update a SCHEDULED source on a Tabelle — the agent parity for ‘Geplante Quellen’. To CREATE: table + a source module id + a cadence. To UPDATE: table + source_id + the fields to change. A config edit REPLACES the stored config wholesale and is re-validated exactly like create — so read the current config with workspace_table_list_sources, change it there, and send it back WHOLE; a partial config is refused, never merged. Fields other than config (cadence, caps, label) patch independently and leave the config untouched. A newly created source defaults to cadence ‘off’ (INERT) — nothing runs until you set a cadence. For source: 'pool' (create mode) pass industry/company_size_min/company_size_max/country alongside query — otherwise every recurring run re-fills on text similarity alone. A scheduled PAID source (scraping/lead_sourcing) REQUIRES a positive max_credits. ‘job_change’ runs ONLY here, never one-shot, and produces LEADS (recently-joined decision-makers). ‘social_listening’ is the LinkedIn keyword MODULE: config { playbook_id, keywords[], min_engagement?, max_posts? } — it owns its own managed topic (the 3h topics cron never double-scans it) and imports found companies/leads on every due tick. ‘profile_posts’ is the THOUGHT-LEADER module: config { playbook_id, profile_url, max_posts? } — it watches ONE person’s OWN posts and imports everyone who engaged as LEADS, one row per person. Take ‘profile_posts’ when the customer publishes on LinkedIn and wants their audience worked, ‘social_listening’ when you want OTHER people’s posts found by search terms. The cron dispatcher re-fills the table from due sources; icp_playbook_id makes a ‘scraping’ source rotate its terms out of an ICP instead of repeating one query forever.
workspace_table_stop_run
Stop every in-progress run on a Tabelle (workspace database table) — the mirror of workspace_table_run_column. Flips the table’s ‘running’ runs to ‘cancelled’ and skips their still-queued cells; the worker checks the cancelled status before each remaining cell and halts, so NO new cell starts and no further Credits are spent (an already-executing cell may finish). Idempotent — returns { aborted_run_ids: [] } when nothing is running. table accepts a name or id. OrgScope-bound: only this workspace’s runs can be stopped.
workspace_table_update
Update a Tabelle’s table-level settings — its name, description, its folder (the Mappe grouping tables on the overview; null/blank removes it, a new name creates the Mappe implicitly), and the CO4 auto_advance toggle. table accepts a name or id. auto_advance is the Ablauf-orchestrator opt-in: when true, inserting a NEW row auto-runs the table’s auto_run ENTRY columns (columns with no upstream deps), so the whole Ablauf self-advances on every new row — it then spends credits without a human in the loop, so leave it off unless that is intended. This is the ONE switch that makes a table run by itself: column-level auto_run pulls the Ablauf along, auto_advance starts it. Column-level auto_run is set separately via workspace_table_add_column. At least one field must be given.
workspace_table_update_cell
Update one manual or relation cell in a Tabelle (workspace database table) row. Columns of kind “manual” take any value matching the column’s data_type. Columns of kind “relation” take the id of a row in the relation’s configured target table as value — it is validated to be a real, in-scope row before the write (an unknown/foreign id is rejected with a clean error, no write); pass an empty value to clear the relation. Every other computed column kind (formula/ai/tool/enrichment/system) is rejected so agents never overwrite a run’s output.
workspace_tables_list
List every Tabelle (workspace database/table) in this workspace with its id, name, entity binding, description, folder (its Mappe/workbook — tables sharing a folder form one workbook; null = unfiled) and row count. Use this to find a table’s id/name before calling the other workspace_table_* tools. fed_by appears when something OUTSIDE the scheduled sources feeds the table — ‘webhook’ (an external tool POSTs rows in), ‘upstream_table’ (a create_lead column of another Tabelle) or ‘workflow’ (an add_table_rows step). It never lists the scheduled sources themselves: a table with no fed_by can still have them, and workspace_table_list_sources is the one call that answers both (sources + inflows) for one table.