# Gravity Builder Documentation > How agents are built and published on Gravity: the assignment guidelines, the workflow engine, supported pieces, AI capabilities, the Publish Gate, and builder questions. This file is the complete documentation as one markdown document, intended for AI assistants and LLM tools. The human version lives at /docs. Gravity is a marketplace for AI agents. Every agent is an Activepieces flow underneath: builders create flows on Activepieces Cloud, export them as JSON, and publish them on Gravity, where end users run private clones of them. ## Agent assignment guidelines The bar every submitted agent is reviewed against: ten rules that separate an agent from a tool. Read these before you build, and check your agent against them before you submit. ### 1. Ask only for one-click sign-ins Every connection your agent needs should be OAuth (Google, Slack, Notion, HubSpot...) or need no account at all (RSS, public pages, webhooks). Assume the person using your agent is non-technical and does not know what an API key is. If a source offers two paths, take the OAuth one. ### 2. Questions to ask the user: preferably four or fewer These are how your agent gathers the context from people which it needs to run. Ask for what the agent genuinely cannot work without as part of the flow, in plain language. Four questions are the max you should aim for, but it can be more if the agent really demands it. The agent itself can be as deep as the assignment demands — the limit is on questions, not on the flow. See the "Builder questions" section for how to select and write them well. ### 3. Create everything the agent needs yourself If your agent works off a sheet, folder, or database, do not ask the user to make one. On its first run, the agent should check whether it exists, and if not, create it: - the exact columns it expects, - one example row filled in to show the format, - and a message to the user with the link and a single line on what to add. From then on, the user only enters data, never structure. Why this matters: a user who builds their own sheet will name a column wrong, and your agent will then fail without anyone understanding why. ### 4. Never make people take extra effort, they just won't do it Users will not do homework for your agent. Take a simple example: an expense tracker that says "upload your bank statement every month." The user does it once, maybe twice, then forgets forever, and the agent goes quiet. Now it looks like Gravity stopped working, when really the agent was waiting to be fed. The fix is to remove the homework completely. That bank statement already arrives in their Gmail every month. The agent should find it there by itself. Same for receipts, invoices, bookings, job alerts: almost everything an agent needs is already sitting in the user's inbox, calendar, or Drive. Go get it. Only ask the user to do something repeatedly in two cases: when they get something back immediately (they add a product, listings appear) or when they are simply replying to a question your agent asked. Everything else, the agent fetches on its own. That is what lets it keep running for months without the user lifting a finger. ### 5. Give it a real trigger A schedule, an inbox event, a file drop, a new sheet row, a webhook. It should be set up once and never need to be started again. The trigger is what makes it an agent instead of a tool. ### 6. Make it remember Each run should save what it did — using the Storage piece, or a hidden tab in its own sheet — so the next run builds on it instead of repeating it. An invoice chaser that forgets it already sent yesterday's reminder spams the client daily. One stored line is the difference between a professional and a spammer. ### 7. Put approval gates where they belong Anything that messages a third party or touches money should wait for a one-tap yes. Everything internal (updating sheets, drafting, logging) runs free. Rule 10 covers the approval patterns and when to use each. ### 8. Check AI-built work before you upload it Building with Claude or ChatGPT is fine, but treat the output as a first draft, not a finished agent. AI assistants confidently reference pieces that do not exist, misname actions, and invent settings that look right. Before uploading, run the whole flow on real data and watch every step succeed with your own eyes. A workflow that has never had a green end-to-end run is not done, no matter how complete it looks. ### 9. Never hardcode anything Anything that changes from user to user (an email address, a sheet, a price, a date) should be a variable that holds the user's own input or a fresh fetch, never a value you typed in while testing. Before uploading, look through your steps for anything specific to you and replace it with a variable. ### 10. Put approval gates where they belong An approval is how your agent waits for a human yes before doing something it should not do alone. Anything that messages a third party or touches money should wait for one; everything internal — updating sheets, drafting content, logging — runs free, with no approval needed. The platform holds a paused run for hours or days at no cost, so waiting is always safe. There are four patterns, and picking the right one matters more than any other design choice in your agent. Note: an approval asks the user for a yes in the middle of a run. The Publish Gate (see its own section) keeps real actions from firing while the agent is being built or tested. A finished agent usually has both. #### The four patterns - **Approval email.** The Gmail piece (and Outlook, for users who live there) has a Request Approval in Email action: it sends the user an email showing exactly what is about to happen, with Approve and Reject links, and pauses the flow until one is clicked. This is the default pattern. The email must show the actual thing being approved — the full drafted message, the amount, the recipient — never a vague "your agent wants to proceed". For a batch, send one approval email summarizing all of it, not one email per item; ten approval emails a day is how users stop reading approval emails. - **Slack approval.** The Slack piece has the same request-approval actions as buttons in a DM or channel, plus a request-action variant with custom buttons for decisions that are not a plain yes or no ("Send now / Skip / Ask me later"). Use it when the user already lives in Slack; otherwise use approval email. Equivalent actions exist for Microsoft Teams, Discord, and Telegram when a bounty's audience lives there. - **Editable draft.** Approve and Reject links are binary — the user cannot change the message before it goes. When your bounty says the user tweaks drafts, or the agent learns from edits, do not use an approval email. Create the draft in the user's own Gmail drafts folder instead: they edit and send it themselves, and your agent watches sent mail to see what actually went out. The difference between the draft and the sent version is also your learning signal. - **Reply confirmation.** When the agent needs information rather than permission — "did this client pay you?", "which folder do you keep these in?" — it asks by email and reads the reply in the same thread. Write questions a person can answer in one line. #### Which pattern when | The bounty says | Use | | --- | --- | | "queued for my one-tap approval", "waits for my yes" | Approval email | | "approve the whole batch in one tap" | One approval email covering the batch | | "I tweak it before it sends", "it learns from my edits" | Editable draft | | "ask me and I reply", "confirm with me once" | Reply confirmation | | The user works out of Slack all day | Slack approval | #### Rules that apply to every pattern - An approval that never comes back must not break anything: the run should time out gracefully, remind once at most, and never act as if silence meant yes. - If your agent supports graduation — routine messages earning auto-send after repeated unedited approvals — graduation applies to one specific approved template, the user switches it on explicitly, and rejections, offers, negative-review replies, and anything involving money can never graduate. The one narrow exception is defined by the bounty catalog itself: post-payment receipts on a once-approved template, only on an exact invoice-and-amount match. #### Do not use - **The piece named "Approval (Legacy)".** It is deprecated and marked legacy in the piece catalog. AI assistants building workflows reach for it first because of its name — do not let them. Use the channel-native approval actions above instead. - **The Chat UI trigger** (on the Human Input piece). Published agents cannot use it; use the Web Form trigger when a flow needs structured human input at its start. Coming: an in-app approval surface, built on the platform's Todos capability, is in development. When it ships, it becomes a fifth pattern and the recommended default. Bounty specs and existing agents will not need to change — bounties name what the user experiences, and this page owns how it happens. ## Quick reference | Topic | Key fact | | --- | --- | | Engine | Activepieces (self-hosted); agents are AP flows, consumers run private clones | | Blocked pieces | Commercial AI providers: OpenAI, Azure OpenAI, Azure AI Foundry, Anthropic, Claude, AWS Bedrock, Google Gemini, Vertex AI, Mistral, Cohere, Perplexity, Groq, DeepSeek, Grok | | Also unsupported | Chat trigger; file upload; Activepieces Tables and Database; audio files; Cloud-only pieces; unknown piece slugs (checked at publish) | | AI | One universal AI piece, six actions (Ask AI, Summarize, Generate Image, Classify, Extract Structured Data, Run Agent) via managed OpenRouter; swapped to metered gravity-piece-ai at publish | | Publish Gate | Optional right now (publishing works without it); when present, real actions below it never run in builds or previews | | Builder questions | Ask-user switch per field at publish; plain-language question text written by the builder | | Bind | One answer fans out to the same property across selected nodes | ## The workflow engine ### What is Activepieces Activepieces is an open-source workflow automation platform. A workflow (called a flow) starts with one trigger and runs a chain of steps. Each step comes from a "piece": a TypeScript npm package that describes one app or capability, with its triggers, actions, input properties, and authentication. Gravity runs its own Activepieces instance; every published agent on the marketplace is an Activepieces flow underneath. ### Activepieces vs n8n n8n is a comparable automation tool, and Gravity's first workflow engine actually parsed n8n exports. The platform has since moved fully to Activepieces. The differences that matter: | Aspect | Activepieces | n8n | | --- | --- | --- | | Integration unit | A piece: a versioned npm package. New pieces install into a running instance at runtime, no redeploy. | A node, bundled with the n8n release. Custom nodes require packaging into the instance. | | License | MIT (permissive) for the core and community pieces. | Fair-code (Sustainable Use License); not fully open source, with limits on commercial hosting. | | Multi-tenancy | Built-in platform and project model: each user gets an isolated project with their own flows and connections. | Primarily single-team; multi-tenancy requires enterprise or separate instances. | | Templates | Flows export and import as clean JSON templates. | Workflow JSON exists but is tied closer to instance state. | ### Why Gravity chose it Each consumer gets a private clone of an agent inside their own project; Gravity's custom pieces (the Publish Gate and the metered AI piece) ship as public npm packages and install at runtime without forking every deployment; and the marketplace itself is built on template export and import, where a builder uploads the exported JSON of their flow. ## Supported and blocked pieces Two different rules apply. First, a piece must exist in Gravity's Activepieces instance: at publish time every piece in the uploaded workflow is checked, and any piece that cannot be resolved is rejected with the message "Workflow uses pieces we don't support yet". Second, some pieces exist but are deliberately blocked by policy. ### Blocked by policy: commercial AI provider pieces Agents must run their AI through Gravity's managed AI, so pieces that would run on the builder's own API key or cloud account are blocked. They are hidden from the app-connection catalog and rejected when a workflow containing them is published. | Provider family | Blocked pieces | | --- | --- | | OpenAI and Microsoft | OpenAI, Azure OpenAI, Azure AI Foundry | | Anthropic | Anthropic, Claude | | Amazon | AWS Bedrock | | Google | Google Gemini, Google Vertex AI | | Other commercial LLM APIs | Mistral AI, Cohere, Perplexity, Groq, DeepSeek, Grok (xAI) | Two deliberate exceptions: open-source and open-weight model hosts (for example Hugging Face and Stability AI) are allowed, and Gravity's own managed AI path (the universal AI piece, gravity-piece-ai, and the OpenRouter gateway it routes through) is never blocked because it is the intended way to use AI in agents. ### Not supported for other reasons | What | Detail | | --- | --- | | Chat trigger | The chat interface trigger (piece-forms, chat_submission). Published agents must start from a supported trigger; use the Web Form trigger instead when the agent needs user input at run time. | | File upload | Users cannot upload files to an agent. Collect the content through the matching app instead: a Google Sheet for CSV data, a Google Doc or Word file for documents — the same pattern for any file type. | | Activepieces Tables | The built-in Tables product is not available. Use Google Sheets instead — it does the same job, and the agent can create the sheet itself on its first run. | | Activepieces Database | Not available on our instance. Use a real database piece instead, such as MongoDB or Oracle. | | Audio files | Agents cannot receive or process audio. There is no workaround yet. | | Activepieces Cloud exclusive pieces | Pieces that exist only on Activepieces Cloud and are not published to the public registry (for example Cloud-only premium integrations). They fail the availability check at publish. | | Unknown or unpublished custom pieces | Any piece slug our instance cannot fetch from the npm registry. | Often confused with unsupported — but supported: the Cloud AI category pieces (text-ai, image-ai, utility-ai, agent). Activepieces Cloud splits its AI actions across these four slugs; Gravity's instance bundles the same actions in a single piece. Templates using them are accepted and rewritten automatically, including known action renames (for example summarize becomes summarizeText). ### Supported triggers Web Form, Webhook, Schedule, Manual, and app piece triggers (both polling and webhook styles). ## AI capabilities ### The six AI actions All AI in agents runs through one capability: the universal AI piece. In the step picker it appears under the "AI & Agents" tab and offers six actions: | Action | What it does | Typical use cases | | --- | --- | --- | | Ask AI | Free-form text generation from a prompt. The workhorse action. | Writing posts, emails, replies, product descriptions; any "take these inputs and write X" step. | | Summarize Text | Condenses a long text into a short one. | Digesting articles, RSS items, meeting notes, or long email threads before delivery. | | Generate Image | Creates an image from a text prompt. | YouTube thumbnails, social post visuals, illustrations. | | Classify Text | Assigns a text to one of a set of categories. | Routing incoming email (inquiry, complaint, spam), triaging form submissions, tagging content. | | Extract Structured Data | Pulls typed fields out of free text. | Turning a form answer or email into fields such as role, seniority, and skills; parsing receipts or job posts. | | Run Agent | Runs a multi-step AI agent that can reason and use tools to complete a task. | Open-ended tasks where a single prompt is not enough, such as research-and-draft flows. | ### How this maps to piece slugs | Piece | Role | | --- | --- | | Universal AI piece (@activepieces/piece-ai) | Carries all six actions above on Gravity's instance. | | Cloud AI category pieces (text-ai, image-ai, utility-ai, agent) | The same actions as exported from Activepieces Cloud, split across four slugs. Accepted at publish and mapped automatically to the universal piece. | | gravity-piece-ai | Gravity's metered copy of the universal AI piece. Identical actions; every call is measured so the run can be charged in credits. The platform swaps AI steps to this piece automatically at publish and clone time. Builders never add it by hand. | ### How models are provided AI steps run through Gravity's managed AI provider (OpenRouter). Builders need no API key, and there is nothing to connect. Commercial provider pieces (OpenAI, Anthropic, Azure, and the rest of the blocked list) cannot be used instead; open-source model hosts such as Hugging Face remain available for builders who specifically need them. Troubleshooting — "No allowed providers are available for the selected model": if an AI step fails with this error while building on Activepieces Cloud, the model picked is restricted on their side — it is not fixable in the flow. Switch the step to a different model; if the error persists, contact Activepieces support to find out which models the account can use. ### Trim what you feed the AI The most common failed run we see: a small, fast model with an entire scraped web page dumped into its prompt. Every model has a context limit, and blowing past it does not degrade gracefully — the step errors out or returns nothing, usually only on real data, after the agent is live. - Cut before you prompt. Pass the part the step actually needs, not the whole page, email thread, or document. Use Extract Structured Data or Summarize Text as an earlier step to boil raw content down first. - Match the model to the load. Small models are for small, well-trimmed inputs. If a step genuinely has to read a lot of text, pick a model with a large context window — do not hope a small one copes. - Test with worst-case input. A two-line sample proves nothing; run the step on the longest, messiest page or thread it could realistically receive. ## The Publish Gate piece The safety piece that keeps real actions from firing while an agent is being built or tested. gravity-piece-publish-gate is a first-party Gravity piece with a single action, "Continue Only If Published". When the step runs, it checks how the flow is executing. The steps below it run only when the automation is published and enabled and is executing its published version — a real run of a live agent. In every other situation (building, draft preview, test runs), the gate stops the run cleanly and reports that the steps after it were skipped. **Currently optional:** you do not have to use the Publish Gate right now — a workflow without it publishes fine. It remains the recommended way to keep builds and test runs from firing real actions. Design properties: - It cannot be bypassed. The piece hides the "continue on failure" and "retry on failure" options, so a failed check can never fall through to the real actions. - The platform forces the strict check at publish and at clone time, so even flows published before the current version behave safely. ### How and where to use it **Never edit your exported JSON by hand.** Add the gate only from the step picker inside the Activepieces flow editor. Do not paste the step (or anything else) into an exported JSON file — hand-edited exports are missing internal fields the editor writes, and they fail to import on upload. If the piece is not available in your Activepieces workspace, simply build without it: the gate is optional, and the platform enforces the same safety behaviour automatically when your agent is published. Place the gate after the trigger and the content-preparation steps, and before every step that has an external effect: sending an email, posting to a social network, writing to a spreadsheet, calling an external API on the user's behalf. Everything below the gate is skipped automatically while the flow is being built or tested, so a builder can iterate freely without spamming real channels. Example layout: Web Form trigger → Generate Image → Continue Only If Published → Respond on UI → Send Message to a Channel. The image generation runs during tests; the delivery steps only run on the live agent. One exception: the pre-publish end-to-end test that gates every publish runs the flow as a genuinely published and enabled automation, so the gate passes and the real actions fire exactly once. This is intentional — it is how the platform verifies the agent actually works before it goes live. ## Builder questions Builder questions are the questions an end user answers before running an agent. The builder defines them during the publish flow, and the answers are injected into the user's private copy of the workflow at run time. They are stored with the agent as its consumer-input schema, so the run page, the chat surface, and the test step all render the same questions. ### How to select them In the publish flow, the "All nodes" step lists every node of the workflow with its input fields. Each field has an "Ask user" switch: - Switch on the fields whose value should come from the end user on every run: the topic of a post, a recipient, a dish name, a preference. - Leave the switch off for configuration that stays fixed: prompts the builder tuned, API paths, formatting choices. Those keep the value wired in the workflow. Form-trigger fields are selected by default. Fields on action steps can also be exposed, including dropdowns whose options resolve live against the end user's own connection (for example a Slack channel list), date, checkbox, number, and list inputs. File-upload fields are not supported. Fields that carry secrets can be marked as secret so the value is masked and stored safely. A practical rule: ask for the minimum the agent truly needs per run. Every extra question adds friction for the end user, and unanswered optional fields simply keep their original wired value. ### How to write the questions After selection, the "Input fields" step shows each chosen field and a box: "Question shown to the user". Guidelines: - Write in plain user language, not field names. "Which role is this post about?" rather than `role`. - One question per field, and state the expected format when it matters: "Any dietary preference? (vegetarian, vegan, gluten-free)". - Use the optional description as helper text under the question, never as a second question. - For choice fields, add options so the user picks instead of typing. ## Bind Bind lets one question fill the same property on several nodes. Next to every "Ask user" field there is a Bind button. It opens a node picker; the builder ticks the other nodes that share the same property, and the binding shows as a badge listing the node numbers (for example "1 - 3 - 5"). At run time the user answers once, and the platform writes that single answer into the matching property on every bound node. The match is by property name on each selected node, so it works generically across pieces. ### When to use it Use Bind whenever the same value appears in more than one step and must stay consistent: - A Slack channel used by two different message steps. - A recipient email used in a draft step and a send step. - A topic or product name referenced in two AI prompts. - A spreadsheet ID used by a read step and a write step. Without Bind, each occurrence would need its own question. The user would answer the same thing twice, and a mismatch between the two answers would break the run in ways that are hard to see. With Bind the question list stays short and the value is guaranteed to be identical everywhere. ### How to use it 1. In the "All nodes" step, switch "Ask user" on for the field. 2. Click Bind next to that field. 3. In the picker, tick every node where the same property should receive the answer. The field's own node is always included. 4. Confirm. The badge turns green and lists the bound nodes. Bind is fan-out, not merging: it does not merge different properties. The bound nodes must carry the same property (same leaf name), such as `channel` on two Slack steps.