What you can ask
A catalog of what the Avo AI assistant can do, with a prompt for each one. Everything here works in plain language — you never name a tool, and you never have to phrase a request a particular way.
The resource and field names in the examples are placeholders. Substitute your own: the assistant reads your resources, your columns, and your scopes at the moment you ask, so the vocabulary that works is the vocabulary of your admin.
For how a turn actually unfolds — schema, confirmation cards, authorization — see How the assistant works. For the tool-by-tool reference, see Agents and tools.
Add a reusable skill
Paste a skill into the chat and ask "Add this as a skill", or attach a .md or .txt file and ask "Import the attached file as a skill". For example:
Add this as a skill:
---
name: bro
description: Restate the last message in plain human language. Use for /bro.
---
Restate your last message simply and concisely, without jargon.The assistant shows the title, description, and full instructions on a card, and saves the skill when you click Save skill, if you have permission to create skills. It does not overwrite existing skills or apply the new skill automatically. Reload the page to refresh the skills menu, then select it to use it. Only .md and .txt files can be imported. See Import a skill.
Find records
| Ask | What you get |
|---|---|
| "Find the user with the email ada@example.com" | The matching record, named inline as a chip you can click |
| "Find the user called John Deere" | The record — found by search, even when the name lives across several columns |
| "Show me the 5 most recent posts" | A short list, sorted by the timestamp that matches what you asked about |
| "Which users signed up in the last 7 days?" | A date-filtered list, resolved against the real current time |
| "List projects whose name contains 'orbit'" | A partial-match list |
| "Show me every column for post 42" | The full record, not just the common columns |
| "Who signed up last?" | One record, named inline as a chip |
| "Show the latest done project and include its visibility" | A project chip with its current visibility added |
| "Which cities have more than one million people?" | City chips with their current population added |
Ranges, sets, and emptiness all work in the same sentence-shaped way: "orders over $500", "users older than 26", "posts with no author", "projects in draft or review".
Naming a record in words is enough. "The user called John Deere", "the post about pricing", "find Acme" — the assistant looks the record up the way your admin does: a resource that configures search gets that exact search, and one that doesn't is matched across every text column you're allowed to read, where a column the Index doesn't show only matches records you may open. A multi-word name still finds the record when its words live in different columns, so a first and last name stored separately aren't a problem. And "no such record" is only ever reported after that search came back empty — never off a guessed column filter.
Your scopes are part of the vocabulary. Domain words like "admins", "active", or "published" are usually named scopes on the model rather than columns, and the assistant prefers the scope over guessing at a filter — so "list the published posts" runs Post.published, whatever that scope actually does.
Associations, without SQL. "Which teams have no members?" and "show me users who have at least one order" are answered by checking whether the association exists, scoped to the child records you're allowed to see.
Records are named inline. Any record the assistant mentions is rendered as a chip in the sentence itself — its picture, its title, and whatever its resource declares — and clicking it opens the record. So "who signed up last?" reads as one sentence with the person in it, not as a paragraph followed by a card. When the resource enables dynamic fields, ask about population and the city chip can carry population; ask about continent and it can carry continent instead.
A chip appears because the assistant named that record in its answer, which is why a count never brings one along: "how many projects?" names no project, so it shows none.
Ask for several and they come back as a list of rows — "the last three users" is three rows you can scan and click, not a bulleted paragraph.
The resource supplies the chip's stable parts and decides whether the assistant can append answer-specific fields — see Record chips.
You can also ask the onboarding assistant to make those chips distinctive: "Give paid purchases a green chip and refunded purchases a red one", "Use an indigo-to-fuchsia gradient on city chips", or "Use each event's cover as its chip background." It updates the resource's def chip declaration, where the result remains ordinary app code you can adjust.
Count and break down
Counts come from the database, never from counting the rows on screen.
| Ask | What you get |
|---|---|
| "How many orders do we have?" | The total |
| "How many posts per status?" | A count per value |
| "Which team has the most members?" | Grouped counts, highest first |
| "Which author has published the fewest posts?" | Grouped counts, lowest first |
| "How many users signed up per month?" | A count per day, week, or month, in your app's time zone |
| "How many distinct customers placed an order?" | Distinct values of a column, not rows |
| "How many members does the Core team have?" | Only the records belonging to that one parent record |
A "how many" question reads no records. It goes to a counting tool that returns numbers and nothing else — no ids, no names, no column values — so answering it sends none of your data to the model provider. The same filters, scopes, and search apply as when listing records, and the answer says what was counted: "412 orders placed this month".
Counting within a parent record goes through the same checks as opening that record's association in the admin: you have to be allowed to see the parent, to view it, and to view that association. A column hidden from you can't be counted by, grouped by, or filtered on either — a count over a column you can't see would still tell you what's in it. For the same reason, a count by a column the Index doesn't show includes only the records you may open.
A count that runs longer than 10 seconds on PostgreSQL is stopped and reported as an error. You get a request to narrow it, never an estimate.
If a list is longer than one page, the assistant says so — "showing 25 of 54" — instead of quietly presenting a subset as the whole.
Look around your admin
| Ask | What you get |
|---|---|
| "What can you help me with?" | A short description of what it does here |
| "Which resources are there?" | Every resource you're allowed to see |
| "What fields does the Post resource have?" | Fields with their types, plus associations, scopes, and attachments |
| "What columns are on the users table?" | Columns, indexes, and foreign keys |
| "Which actions can I run on projects?" | The actions that resource registers, and the inputs each takes |
All of it is scoped to what you could already reach in the Avo UI. A resource your policies hide doesn't show up here either.
Create records
Creates apply immediately — there's nothing to preview for a record that doesn't exist yet.
- "Create a project called Orbit" — the assistant asks only for values it genuinely needs, and never for optional fields you didn't mention.
- "Add a user named Ada with the email ada@example.com and the admin role" — several fields in one sentence.
- "Add 15 cities" — creating is the one write it repeats. It creates all fifteen without stopping to ask between them, filling required fields with sensible values, and closes with one line.
Each created record gets its own card with a link. The one create that waits for you is an import from a file — "create users from this CSV" shows a card first; see Work with files.
Change and delete records
Deletes work one record at a time. Updates work on one record or on many, and either way it ends in a card you confirm.
- "Set the Orbit project's status to active" — a card shows the record and each field's before → after value, with Confirm and Cancel.
- "Rename the post 'Hello' to 'Hello world'" — same card.
- "Update the last three users and make them active" — one card for the whole batch: the change once, then every record it will touch, with the same Confirm and Cancel.
- "Show me this week's signups. Mark them approved" — the assistant looks them up first, then proposes the batch. If your app registers an approve action, it runs that instead, because an action carries business logic a field edit doesn't.
- "Delete the test project" — a card names the record and asks you to confirm.
A batch is one card, one confirmation. Up to 50 records at a time by default (config.ai.max_update_records raises it to 500); ask for more and the assistant says how many there are and offers to narrow. Records that fail validation are named on the card afterwards and the rest are still updated. Each record's change is recorded on its own, but the batch stays one entry in the history: "undo that" takes the whole batch back on one card, and you can ask to undo only some of its records.
Your confirmation applies the change, not the model. Confirm a card by clicking its button or by telling the assistant to go ahead — "do it", "run it", "yes" — which counts the same because the words are yours. Either way the assistant can propose a write but never perform one, and it can't talk its way past a Cancel.
Ambiguity stops the write. If "the Orbit project" matches three records, the assistant lists them and asks which one rather than picking — naming one record and getting several is a reason to stop, not to update all three. Deleting many records at once isn't offered: ask and it will say it deletes one at a time.
Undo something
Every executed write is recorded, so undo doesn't depend on the change still being visible in the conversation.
| Ask | What happens |
|---|---|
| "What have you changed in this chat?" | The writes made here, newest first |
| "Undo that" | A card describing the undo, for you to confirm |
| "Revert the status change on Orbit" | The same, for a specific earlier write |
| "Undo that bulk update" | One card listing every record in the batch; hover a record to see what it restores |
| "Undo the batch, but only for Orbit" | The same card, narrowed to the records you name |
Undoing a create deletes the record it made; undoing an update restores the values it overwrote; undoing a delete re-creates the record. A write can only be undone once, and a change that left nothing behind to restore is reported as not undoable rather than attempted.
Undoing a batch is one Undo click for every record in it. Each record is checked again when you click: one you may no longer edit, or one someone changed after the batch, is skipped and named on the card, and the rest are restored. An undo card that's already waiting is not proposed twice. If you ask again, the assistant points you at the card on screen.
Run your actions
The assistant runs the actions your resources register, so operations keep their business logic instead of being reconstructed field by field.
- "Archive the Orbit project" — finds the matching action, reads its inputs, and shows a confirmation card with the action's own fields rendered on it, prefilled with any values you named ("...reason: budget cut") and editable before you run.
- "Publish this post" — runs your publish action, notifications and all, rather than setting
published_atbehind its back. - "Export the users as CSV" — actions that run without records work too.
- "Which actions does this resource have?" — lists them with their inputs when you'd rather look first.
Required inputs you didn't mention arrive as empty fields on the card for you to fill; the assistant never invents a value for them. Full detail in Your actions, from the chat.
Work with files
| Ask | What you get |
|---|---|
| "How much storage are we using?" | Totals by service, content type, and resource |
| "Any orphaned uploads?" | Blobs attached to nothing |
| "Do we have duplicate files?" | Files sharing a checksum, and what de-duplicating frees |
| "Is storage growing?" | Uploads per month |
| "What are the biggest files?" | The largest files and which records they belong to |
| "Which products have no image?" | Records missing an attachment |
| "Show me this post's cover" | The file itself — images inline, video and audio with a player |
| "Show me the beach photo" | A search by filename across everything you can see, Media Library files included |
| "Attach blob 42 to this post's cover" | The file linked to the record |
| "Attach 260 to this post's cover" | The same, from a Media Library URL — its id is the blob id |
| "Attach the file I just sent to the cover" | A file you uploaded in this chat, linked to the record |
| "Attach https://example.com/logo.png as the cover" | A confirmation card with the URL and a preview — nothing is fetched until you click Attach |
| "Take the cover off this post" | The file unlinked — the blob stays in the Media Library |
| "Read this contract and tell me if the subscription is active" | The file read, the subscription looked up, and an answer grounded in both |
| "Which of the emails in this CSV are signed-up users?" | The rows read in windows and matched against your records — matches and misses reported |
| "Create users from this CSV" | A card with the file, the mapping, and a preview of the first rows — nothing is created until you click Confirm |
Files are referenced by blob id, and the Media Library URL carries one: /avo/media-library/260/edit is blob 260. The assistant never uploads bytes itself — a file gets in either by riding along on your message or through a URL you confirm. Purging a file stays a manual action. See Files and attachments and Getting new files in.
Reading a file works wherever the file lives. A file you dropped into the chat, a file attached to a record you can read, and a Media Library file can all be read — markdown, plain text, CSV, TSV, and JSON. The assistant reads in windows (lines, or rows for CSV and TSV) rather than swallowing the whole file, so a long file is read a piece at a time and cross-referenced against your records as it goes. Spreadsheets and PDFs aren't read this way; a PDF still reaches a vision-capable model as an attachment.
Importing shows you the import before it happens. "Create users from this CSV" reads the header, maps the file's columns to the resource's fields, and shows a card with the file and where it came from, the resource, the row count, the mapping, and a preview of the first rows. Nothing is created until you confirm. Rows are then created on the server, one create per row, and the card reports how many were created and lists any row that failed validation with its row number and reason — the rest are still created. See Reading files and importing from them.
Ask about the page you're on
Start a chat from a page whose subject is one thing and "this" is already resolved — for the whole conversation, not just the first message.
From a record's page:
- "What is this?"
- "Who owns it?"
- "Set its status to active"
- "Is anything missing here?"
From one Media Library file's page:
- "What is this?"
- "Where is this used?" — every record the file is attached to
- "Attach this to the latest post's cover"
From a conversation's page, starting a new chat from the bar:
- "Summarize this"
- "What did we decide here?"
A ribbon above the composer names the subject, and the ✕ at its end — or Backspace in an empty composer — starts the chat without it; Backspace again brings it back. See What you start the chat from.
Ask about the rows you checked
Check rows on an index — or in a has-many panel on a record's page — and "these" means exactly those records, by id, with no second search.
- "What are these?"
- "How many of these are unpaid?"
- "Set all of these to archived" — one card over exactly the rows you checked, with no second lookup
- "Which of these has no owner?"
The ribbon's "3 records selected" chip says how many; hovering it names each row by resource and label. See The rows you checked.
Ask about a file you sent
Attach files to your message — paperclip, drag, or paste — and ask about them directly:
- "Summarize the attached CSV"
- "What's in this screenshot?"
- "Create a project for each row in this CSV" — an import card you confirm; see Work with files
The files stay on the message, so you can keep asking about them later in the conversation. Text files — markdown, plain text, CSV, TSV, JSON — are read on demand, in windows, rather than sent to the model whole. Reading an image or a PDF takes a vision-capable model. See Send files with a message.
Reach your other systems
If your app lets you connect MCP servers, type /mcp and a server's address to connect a tool like Linear, Notion, or Stripe. Its tools then work beside Avo's own, with the record you're on as context. See Connect other tools with MCP.
| Ask | What you get |
|---|---|
| "Give this customer a $30 credit" | The customer found in Stripe from what the record holds, then a card showing the exact call before anything is sent |
| "How can I refund this customer?" | Your own refund policy, read from the Notion pages you connected, rather than a guess |
| "Create an issue about this project not being able to finish on time" | A Linear issue written from the project record you're on, on a card you approve |
| "Mark this project open in Linear, charge the customer in Stripe, and open a GitHub issue for each of its tasks" | Three systems in one turn, a card for each call you haven't always-allowed, and a plain report of anything you declined or that failed |
The record you're on is the identifier. "This customer" resolves from what the record already holds, such as a Stripe id or an email. When the record holds nothing that names the remote entity, the assistant looks it up on the other side or asks you which one. It doesn't guess an id.
Say which system when it matters. Two servers can offer tools with the same name, and so can your admin. Saying "in Linear" or "in Stripe" saves a round trip, and the assistant says which connection a result came from.
One card per call. A request that touches several systems shows a card for each call, so you can approve the Linear issue and decline the charge. Declining stops that call only: the assistant carries on with the rest or explains what it couldn't finish.
A connection that's down doesn't break the chat. Avo's own tools keep working, and the assistant names the connection that failed instead of going quiet.
Manage the conversation
- "Rename this conversation to 'Q3 invoices'" — your exact wording, applied everywhere the title shows.
- "Rename this conversation" — with no name given, a fresh title is generated from where the conversation actually went.
New conversations title themselves after your first message. See Renaming conversations.
You don't have to ask, either. The ⋯ menu next to the title renames the conversation without the assistant — Rename chat to type the title yourself, Rename with AI to have one generated — and the bar's menu adds Copy as markdown, which puts the conversation on your clipboard as plain text. See The conversation menu.
What it won't do
Knowing the edges saves a round trip:
| It won't | Because |
|---|---|
| Delete many records at once | Deletes are one record at a time; it will ask you to pick. Updating many at once is supported — see Change and delete records |
| Apply its own updates, deletes, or undos | The card is yours to confirm — a click, or a quick "do it" in your own words |
| Delete a file from storage | It can detach, never purge |
| Touch anything your policies hide | Every read and write is authorized for the signed-in user |
| Take on substantial work unrelated to this app | Writing your blog post, debugging a codebase, a long translation, or a research report is someone else's job — it says so and offers what it can do instead |
| Connect, share, or disconnect an MCP server | Those are clicks in the /mcp panel, behind your app's permission. Ask it to connect something and it tells you where to do it |
| Approve its own call to a connected server | The card is yours, and it takes a click: a typed "do it" never approves a remote call |
| Change what a connection's tools may do | On, Always ask, and Off belong to whoever manages the connection, on its page |
Short of that it is good company: small talk, a joke, a quick factual aside, or a question about a file you dropped into the conversation all get a straight answer before it steers back to your data. Anything you put in front of it — an uploaded file, the Media Library file you started the chat from, text you pasted — counts as part of the conversation, so "what does this show?" is answered rather than declined.
A record you can't reach reports as "not found" rather than "not allowed", so the chat can't be used to probe for what exists.