Tool search 164,478 tools · 10,067 live servers
Filtersactive
- generate_cast
Writes the CAST for an AI Video Story series - named characters with a role and a one-line description each - and returns it as a DRAFT for the user to read. FREE: this call spends no tokens. It generates no portraits and saves nothing to the user's character library. WHAT IT ACTUALLY RUNS: a showrunner model reads the series and the idea you passed and answers with the cast that idea needs - who those people are, how they relate, what species the series casts them as. IT DOES NOT WRITE THE STORY. When you pass an `idea`, the response's `idea` field is the one you sent, unchanged (translated into the output language if it was in another one); the plot is written later, by `generate_story_video`. If you pass NO `idea`, the call authors a logline itself and the `idea` field is that logline - the only case where it comes back with something you did not send. Same call the webapp's cast step makes. Nothing is charged for any of it. WHEN: as soon as the episode idea is settled, on a series whose `cast.required` is true (or whose user wants custom characters). Do NOT ask permission first - it costs nothing, and the webapp writes this roster automatically at the same point. A series with `cast.writer_owned: true` casts itself at episode-write time; never call this for it. AFTER: show the user the names and roles, one short line each - the cast is the whole review. Do NOT present the `idea` field back to them as news when you passed one in: it is their own idea and saying otherwise invents a change that did not happen. The one exception is the no-idea call, where the `idea` you get back IS the logline the writer chose and the user has not seen it yet - show them that one and ask whether to keep it. If they dislike the roster, call this tool AGAIN with a sharper `idea` - a re-draft is free and replaces it, exactly like the webapp's 'Rewrite cast'. Never buy portraits for a cast the user has not accepted. THE PRICE OF THE NEXT STEP RIDES THIS RESPONSE: `portraits_needed` is how many faces are missing - it counts exactly the members whose `needs_portrait` is true, because a preset-bound member arrives photographed and costs nothing - and `portrait_models` lists every image model that can draw them, each with `per_portrait_tokens` and the roster's `total_tokens` on it (the `default: true` entry is what the series is tuned for). Use those numbers verbatim in the message where you ask for the go - do not multiply anything out yourself. THEN: `generate_cast_portraits` with this response's `draft_id` mints the portraits. That call is the money. The draft stays redeemable for about two hours; after that write a fresh one (free). NOT ON THIS SURFACE (the aicut webapp owns them today): renaming a cast member, adding your own character, and adding one from a photo. Say so if the user asks - do NOT re-draft the whole cast to work around a single member, and do not try to steer one member by rewording the idea. CHANGING what a member IS is available once the portraits are bought: `describe_cast_member` rewrites one member's look for one portrait's price. REFUSALS you act on, all 400 `invalid_request` except the last two - the message says which: the series is unknown or unavailable; the series SHIPS ITS OWN FIXED CAST, so there is no roster to write and none to buy; the series casts itself at episode-write time (`cast.writer_owned` on `list_series` predicts this one); or the series does not support a cast-first flow at all. In every one of those, go straight to `generate_story_video` without a cast rather than retrying with different wording. 429 `utility_rate_limited` / `utility_globally_limited` = this call is FREE but not unlimited - it spends a rate-limited AI-writing allowance shared with the webapp, and the answer is to wait the `retry-after` (about a minute for a burst, a rolling day for the account's daily cap), never to top up tokens. 503 `casts_unavailable` = transient, try again. BREVITY: lead with the ONE decision you need from the user, and keep at most one short paragraph before the question. Never re-explain the staged flow (cast -> frames -> fire -> render) once it has been explained in this conversation - after that, name only the next step. When suggesting episode ideas, offer at most 3, one line each. OUTPUT: this returns JSON for you to read. When you report back to the user, give them the media URL plus a one-line summary. Do not paste the raw JSON, job ids, or internal field names into the conversation.
- change_story_scene
CHANGES WHAT HAPPENS IN ONE SCENE of an AI Video Story episode parked at frames review, and redraws that scene's opening picture from the change. You pass a PLAIN SENTENCE saying what should be different - 'the kid should look super sad', 'move it outside at night', 'she should be holding the letter' - and aicut rewrites that scene's own setting / people / action text from it and draws the new picture. Costs ONE image generation. The change STICKS: the scene video generated at fire is made from the changed scene, not just the picture. WHAT IT CAN CHANGE, AND WHAT IT CANNOT - check the user's ask against this BEFORE you call. IT CAN change the scene's SETTING (where and when it happens), its ACTION (what happens) and WHO IS IN FRAME. IT CANNOT change the SPOKEN LINES / dialogue, the scene's LENGTH, or a scene pinned to a reference still - all three are the aicut web editor's (aicut.pro). An instruction that is ONLY about what somebody SAYS ('change her line to ...', 'he should say it differently', 'make the dialogue shorter') is REFUSED here: 400 `dialogue_only`, nothing written and nothing charged - tell the user the dialogue is edited in the aicut web editor and offer a visible change instead. An instruction that MIXES a line with a visible change ('change his line and move it outside at night') applies the VISIBLE half only, and the response says so - relay that; do not let the user believe the line changed. REPORT WHAT CHANGED, VERBATIM. The response carries `changed` - which of the scene's parts actually moved, and it can be `[]` - and a `report` sentence. RELAY THE `report` AS IT IS WRITTEN rather than narrating a success: an empty `changed` means this call moved NOTHING about the scene, and the new `image_id` on that answer is not evidence that it did. This exists because it went wrong on a live episode: a spoken line was asked for, this tool answered with a fresh picture, the agent reported it as done, and the line was word for word what it had been. THIS IS THE TOOL FOR 'change scene 2, X should be Y'. It is NOT `regenerate_story_frame`, which draws the SAME scene again from the SAME text - another attempt at the picture that is already wrong - and it is NOT a reason to start the episode over. If the user does not like the PICTURE (bad hands, odd framing, a face that came out wrong) that is a redraw; if they do not like WHAT IS HAPPENING, it is this. YOU DESCRIBE THE CHANGE, AICUT WRITES IT (hard rule, the same one as everywhere else on this surface): you never author scene text, image prompts or episode JSON. There is no field here for a prompt, a setting or an action - only the sentence. Pass the user's own words, tidied into one sentence; do not translate them into scene-writing vocabulary, and do NOT read the rewritten text back to them - apply the change and show them the new picture. WHEN: `get_video` shows `story.stage: "frames_review"`. `scene_index` is that scene's `scene_index` from `story.frames`, zero-based - the card and the user count scenes from ONE, so 'scene 2' is the SECOND entry in `story.frames` and you pass THAT entry's `scene_index`. Each frame carries the scene's `summary` (what happens) and `dialogue` (what is said), which is what you check the user's ask against before you spend. AFTER: returns `image_id` with status `generating` and `changed` naming which parts of the scene moved. THIS CALL OPENS ITS OWN CARD, which shows the episode's scene rows with that scene marked as redrawing and fills the new picture in by itself - so do NOT call `show_generation` afterwards to put a fresh set of rows up, and do not narrate the wait. Poll `get_video` only if you need the outcome in your own answer: the lane's `regenerate` entry shows the redraw, and once it succeeds the frame's `url` IS the new picture. CHECK `attached`: if it comes back `false` the image still generates and is still CHARGED but will NOT replace the frame at fire - say so and redraw that scene before firing. IF THE PICTURE FAILS OR THE ACCOUNT RUNS OUT (402) THE SCENE HAS ALREADY CHANGED: the response carries `changed_text: true`. The episode HAS the new beat and is still showing its old picture - say that plainly, it is not lost work, and `regenerate_story_frame` draws the new one for one image's price. Do NOT send this tool again to 'fix' it, which would rewrite an already-correct scene and buy a second picture. IF THE ANSWER CARRIES `changed_text_unknown: true`, AICUT DOES NOT KNOW WHETHER THE SCENE CHANGED - and neither do you. It is NOT a success and NOT a confirmed change: the call failed somewhere aicut could not read the outcome. Never report it as done and never immediately re-send the change (that would apply it twice). Say plainly that it could not be confirmed, then CHECK: call `get_video` and read that scene's `summary` in `story.frames`. If it does not carry the change, send this tool again; if it does, the scene has the new text with its old picture, so `regenerate_story_frame` draws the new one. `changed_text: true` is the only field that means the change landed - its absence is never evidence either way. REFUSALS you act on (the common ones - always read the `code` you actually get): 400 `dialogue_only` = the ask was only about the spoken lines, which this tool does not own - nothing was written and nothing was charged; say that plainly and point at the aicut web editor. It comes back from an `estimate_only` call too, in place of a price. 409 `frame_regenerating` = this scene already has a redraw running, wait and poll `get_video`. 409 `already_fired` / `not_ready_to_fire` / `not_in_review` = the review window is closed or the frames are still generating; a fired episode's scenes are edited in the aicut web editor. 400 `invalid_request` = an invalid or REMOVED scene, an empty or over-long `change`, or a scene whose text cannot be changed here - a scene built from a reference still, and series that write their scenes from a fixed template, both refuse and the message says which. 402 = not enough tokens (see the line above - the text changed anyway). 429 `utility_rate_limited` = the rewriting allowance, not tokens: wait the `retry-after`. 503 `story_unavailable` = transient, try again. COST: one standard image generation, at the series' RESOLVED start-frame model - the same number `regenerate_story_frame` costs, which is the series' `pricing.frame_regen_tokens` on its FULL `list_series` entry (the `series_id` call). `estimate_only: true` is the exact figure and it spends no tokens and changes NOTHING - it does not rewrite the scene. PASS THE REAL `change` WITH IT: a quote that carries the change also checks the instruction and the scene, so an ask this tool cannot carry out comes back as its refusal (`dialogue_only`, or the `invalid_request` for a reference-built scene or a series that writes its own frames) BEFORE you ask the user to approve a spend, instead of after. A quote can still price an ask the paid call then refuses - the check is best-effort and never withholds a number - so a refusal after a go is not a contradiction. That check is a rewriting-allowance call, not a token spend, so a quote can answer 429 `utility_rate_limited`. State the figure before you ask for the go, every time. THE GO THIS ONE NEEDS: one change, one named scene, one priced ask - and the user has to say which scene and what should be different. A complaint ('scene 3 is wrong') is a reason to ASK what should change and OFFER this with its price, never a go to buy it, and a bare 'yes' counts only when your priced ask for THAT scene's change was the message immediately before it, nothing else was raised in between, and nothing the user asked for earlier is still outstanding. Never change more scenes than the user named. Changing a scene is also NOT firing. SPEND ETIQUETTE (the money grammar): in the webapp the priced button is the user's own finger; in chat YOUR tool call is not - so state the price IN THE SAME MESSAGE as the ask, and the user's explicit go is the button press. Never charge on inference: quoting is not asking, and after a price you wait for the yes. THIS APPLIES TO EVERY TOOL CARRYING THIS NOTE, including this one. A GO IS SCOPED TO ONE PURCHASE, AND IT MUST BE UNAMBIGUOUS. The user's instruction has to NAME the thing you are about to buy, or refer to it so plainly that it cannot mean anything else. A BARE AFFIRMATION - 'go', 'yes', 'ok', 'do it', 'just do it', 'sure' - counts ONLY when ALL THREE of these hold: the message immediately before it was YOUR priced ask for THAT EXACT action, nothing else was raised in between, and NOTHING THE USER ASKED FOR EARLIER IS STILL OUTSTANDING. That last one is the trap the others miss: if the user's OWN previous turn asked for something else - a refusal, a different scene, an edit, a redraw, a question - their 'just do it' may be answering THAT, and it is AMBIGUOUS even when your priced ask happens to be the last thing said in the thread. An ambiguous affirmation is not a go: ask WHICH one they mean and state that price again. WHEN IN DOUBT ABOUT WHAT A 'GO' REFERS TO, ASK. A wrong guess spends the user's money on something they never asked for, and nothing on this surface can undo it or give it back - asking costs one sentence. An episode's STAGES - cast portraits, episode create, fire, render - are each their own priced ask. A STANDING GO IS NOT UNLIMITED: 'just make it' or 'go ahead with the whole episode' authorizes the stages you PRICED IN THAT SAME MESSAGE, in the order you named them, and nothing beyond them - so do not re-ask per stage while it holds, and do not stretch it over a stage whose price the user never saw. IT EXPIRES THE MOMENT THE USER RAISES ANYTHING ELSE - a change, a question, a refusal, a redraw, a new idea - and after that the next stage needs its own priced ask. ONE STAGE IS NEVER COVERED BY A STANDING GO AT ALL: the FIRE (`fire_story_video`) is irreversible and the biggest single charge in the episode, so it always takes a go that NAMES firing, whatever was said earlier - see that tool's own note. A REDRAW IS NOT A STAGE: `regenerate_story_frame` and `regenerate_cast_portrait` are extra spends the user asks for one at a time, so state that price every time, even under a standing go. A standing go never carries to a different episode, and never to `generate_video`, `generate_image` or `generate_audio` - each of those is its own ask. ACCOUNT FOR YOUR OWN CALLS: if the user says something happened that you did not intend - a charge they did not expect, a step they did not ask for - RE-READ YOUR OWN TOOL CALLS IN THIS CONVERSATION before you answer, and tell them plainly which tools you called and when. NEVER SPECULATE ABOUT A CAUSE YOU CANNOT OBSERVE: not a button on an aicut card, not the user's own click, not their client. The aicut cards CANNOT SPEND - the only tools they ever call are the reads (`get_video` / `get_image` / `get_audio`), and their buttons either save a file or send a VISIBLE user turn into the chat - none of them calls a spending tool - so saying a card might have generated or charged something is false, not a hedge. (If a spend followed one of those visible turns, it was still YOUR call, and the honest answer names it.) If your call history disagrees with what you told the user, say what you actually called and let them correct you; do not invent an explanation that makes the two agree. IDEMPOTENCY: `idempotency_key` is optional and makes a retry safe. Set it on the FIRST call, not only on a retry - the job is addressed by the key, so a key added afterwards cannot find a job that was created without one. Reusing a key REPLAYS the job that key already created and returns it unchanged - even if you send a different prompt or different settings, and even after that job has finished. A key is therefore spent permanently. Do NOT reuse one to make another generation: two deliberate generations are two jobs and need two different keys (or none). ONE EXCEPTION, on `render_story_video`: replaying a key whose render FAILED answers 409 `render_failed` rather than replaying the failure, because a spent key stays spent - retry that one with a NEW key or with none. A KEY IS NOT SCOPED TO A TOOL: it addresses a job on the whole account, so reusing the key you gave `generate_video` on `generate_story_video` replays that first video instead of starting an episode. One key, one thing you made. (`render_story_video` is the one door that namespaces its own, which is why an episode's key can be reused on its render without colliding - but there is no reason to reuse it there either.) Never derive the key from the request body. You do NOT need to pass one to be safe against a duplicated delivery: aicut already derives a per-call key server-side, so a retry the transport makes on its own replays rather than charging twice. Pass your own only when YOU want to retry a call whose answer you never saw. OUTPUT: this returns JSON for you to read. When you report back to the user, give them the media URL plus a one-line summary. Do not paste the raw JSON, job ids, or internal field names into the conversation.
- generate_image_story
CREATES an AI image story: a narrated script turned into a sequence of AI-generated images, read aloud with captions over it. aicut's most-used format for facts, history, horror, storytime and explainer shorts. YOU WRITE THE SCRIPT, AND ONLY THE SCRIPT. The `text` you send is the narration that gets spoken, verbatim, in that order - there is no writer behind this endpoint. Draft it yourself from what the user asked for, show it to them as plain text before spending anything, and change it until they like it. Iterating on the script costs nothing. What you must NOT write is the pictures: aicut segments your script and writes every image prompt itself. A WORKED EXAMPLE of `text`: `"In 1943 a Soviet pilot was shot down behind enemy lines. He walked eighteen days through the snow on two broken legs. When he reached his own trenches, they did not believe he was alive. Then he asked for his plane back."` That is the whole format: a narration script in plain prose, the way it should be READ ALOUD. No scene numbers, no image directions, no stage notes, no speaker labels - aicut cuts it into scenes and writes the picture for each one. Write it the way a good voiceover sounds: short sentences, a hook in the first line, one idea at a time. PRICE IS DRIVEN BY THE IMAGE COUNT, not by the words. `estimate_only: true` returns `scene_count` and `voice_provider` next to the money - say the count and the price. The three levers, in the order to reach for them: `seconds_per_image` (3 is the default; 5 buys fewer images for the same script and is the cheap direction, 2 is the busy/expensive one), `image_model` (`zit-realism` is the cheap default; `nano-banana-pro` is roughly fifteen times the per-image price - offer it only when the user wants the best-looking result and say what it costs), and `voice_provider` (ElevenLabs reads best and costs about four times openai/polly per character of narration). Re-quote after changing any of the three; never carry an older number across a change. STYLES ARE OPTIONAL AND THEY ARE NOT FREE. `list_image_story_styles` returns aicut's authored looks; passing one as `style_id` forces the expensive edit-capable image model, so re-quote with `estimate_only` after adding one. Without a style you get aicut's default photorealistic look, which is what most videos use. AFTER: the response carries the job id, `scene_count`, the price split (`generation_tokens` for the images and narration, `render_tokens` for the video file) and `renders_automatically: true`. If it ALSO carries `start_confirmed: false`, the job exists but aicut never saw its start confirmed - do not create it again, watch that job id and tell the user it may need a retry if it has not moved in fifteen minutes. THERE IS NO FIRE STEP AND NO RENDER STEP: this one call makes the finished video. Wait for it with `wait_for_generation`; when it is terminal, `get_video` carries the file url. It takes longer than a single image - every scene is generated. LANGUAGE: write `text` in the language you name. aicut detects the script's language and TRANSLATES it when it differs from `language`, and a translated script has a different length - so the quote is exact for the script you sent and only for that. Do not send English and ask for German expecting the quoted price; write the German. REFUSALS (the common ones, not all of them - always read the `code` you actually get): 400 = the script or a setting is not accepted, and the message says which (a script over the language's character limit, which aicut will NOT silently cut for you; a script that needs more images than one video can carry, where the fix is a longer `seconds_per_image`; an unknown style id, model, voice or language). 402 = not enough tokens for the whole video; the body carries `required` and `balance`. 503 `image_story_unavailable` = the video was not started and nothing was charged; retry the same call once. THE WATERMARK is decided by the account's plan, not by this call: free accounts get the aicut mark on the video. Say so if the user asks; there is no argument that changes it. DELIVERY: hand the user ONE thing - the finished video. Do not re-list the script back at them after it is made. SPEND ETIQUETTE (the money grammar): in the webapp the priced button is the user's own finger; in chat YOUR tool call is not - so state the price IN THE SAME MESSAGE as the ask, and the user's explicit go is the button press. Never charge on inference: quoting is not asking, and after a price you wait for the yes. THIS APPLIES TO EVERY TOOL CARRYING THIS NOTE, including this one. A GO IS SCOPED TO ONE PURCHASE, AND IT MUST BE UNAMBIGUOUS. The user's instruction has to NAME the thing you are about to buy, or refer to it so plainly that it cannot mean anything else. A BARE AFFIRMATION - 'go', 'yes', 'ok', 'do it', 'just do it', 'sure' - counts ONLY when ALL THREE of these hold: the message immediately before it was YOUR priced ask for THAT EXACT action, nothing else was raised in between, and NOTHING THE USER ASKED FOR EARLIER IS STILL OUTSTANDING. That last one is the trap the others miss: if the user's OWN previous turn asked for something else - a refusal, a different scene, an edit, a redraw, a question - their 'just do it' may be answering THAT, and it is AMBIGUOUS even when your priced ask happens to be the last thing said in the thread. An ambiguous affirmation is not a go: ask WHICH one they mean and state that price again. WHEN IN DOUBT ABOUT WHAT A 'GO' REFERS TO, ASK. A wrong guess spends the user's money on something they never asked for, and nothing on this surface can undo it or give it back - asking costs one sentence. An episode's STAGES - cast portraits, episode create, fire, render - are each their own priced ask. A STANDING GO IS NOT UNLIMITED: 'just make it' or 'go ahead with the whole episode' authorizes the stages you PRICED IN THAT SAME MESSAGE, in the order you named them, and nothing beyond them - so do not re-ask per stage while it holds, and do not stretch it over a stage whose price the user never saw. IT EXPIRES THE MOMENT THE USER RAISES ANYTHING ELSE - a change, a question, a refusal, a redraw, a new idea - and after that the next stage needs its own priced ask. ONE STAGE IS NEVER COVERED BY A STANDING GO AT ALL: the FIRE (`fire_story_video`) is irreversible and the biggest single charge in the episode, so it always takes a go that NAMES firing, whatever was said earlier - see that tool's own note. A REDRAW IS NOT A STAGE: `regenerate_story_frame` and `regenerate_cast_portrait` are extra spends the user asks for one at a time, so state that price every time, even under a standing go. A standing go never carries to a different episode, and never to `generate_video`, `generate_image` or `generate_audio` - each of those is its own ask. ACCOUNT FOR YOUR OWN CALLS: if the user says something happened that you did not intend - a charge they did not expect, a step they did not ask for - RE-READ YOUR OWN TOOL CALLS IN THIS CONVERSATION before you answer, and tell them plainly which tools you called and when. NEVER SPECULATE ABOUT A CAUSE YOU CANNOT OBSERVE: not a button on an aicut card, not the user's own click, not their client. The aicut cards CANNOT SPEND - the only tools they ever call are the reads (`get_video` / `get_image` / `get_audio`), and their buttons either save a file or send a VISIBLE user turn into the chat - none of them calls a spending tool - so saying a card might have generated or charged something is false, not a hedge. (If a spend followed one of those visible turns, it was still YOUR call, and the honest answer names it.) If your call history disagrees with what you told the user, say what you actually called and let them correct you; do not invent an explanation that makes the two agree. IDEMPOTENCY: `idempotency_key` is optional and makes a retry safe. Set it on the FIRST call, not only on a retry - the job is addressed by the key, so a key added afterwards cannot find a job that was created without one. Reusing a key REPLAYS the job that key already created and returns it unchanged - even if you send a different prompt or different settings, and even after that job has finished. A key is therefore spent permanently. Do NOT reuse one to make another generation: two deliberate generations are two jobs and need two different keys (or none). ONE EXCEPTION, on `render_story_video`: replaying a key whose render FAILED answers 409 `render_failed` rather than replaying the failure, because a spent key stays spent - retry that one with a NEW key or with none. A KEY IS NOT SCOPED TO A TOOL: it addresses a job on the whole account, so reusing the key you gave `generate_video` on `generate_story_video` replays that first video instead of starting an episode. One key, one thing you made. (`render_story_video` is the one door that namespaces its own, which is why an episode's key can be reused on its render without colliding - but there is no reason to reuse it there either.) Never derive the key from the request body. You do NOT need to pass one to be safe against a duplicated delivery: aicut already derives a per-call key server-side, so a retry the transport makes on its own replays rather than charging twice. Pass your own only when YOU want to retry a call whose answer you never saw. OUTPUT: this returns JSON for you to read. When you report back to the user, give them the media URL plus a one-line summary. Do not paste the raw JSON, job ids, or internal field names into the conversation.
- search_music
Find AINSOF music from a written brief — mood, scene, genre, energy, instruments. Example: 'lo-fi hip hop underscore, warm, no vocals'. Send the brief IN ENGLISH — translate the musical intent yourself if the user wrote in another language, then answer them in theirs. Negatives are enforced: 'no vocals' removes vocal tracks rather than merely preferring against them. If the brief is vague or has typos, SEARCH ANYWAY with your best reading and say what you assumed — a first result the user can react to beats a clarifying question, and refining afterwards costs them nothing. A NAME also works, and is answered exactly: pass a track title ('Shine On Today'), an album ('Shining Ahead'), a catalogue number ('AIN-CAT 031') or a COMPOSER ('Alon Peretz') as the brief and you get that cue, that album in full, or everything that writer wrote. A composer named inside an ordinary brief puts their cues first without narrowing it. NEVER tell a user we do not have a track until you have passed its name here.
- check_job
Get the status or result of a job started by deep_research, translate_pdf, or make_slides. Poll every 15-30 seconds until status is "done" or "error". While work is pending, follow retry_after_seconds and next_action; when complete, prefer structured_result when present. Example — GET https://ainetcafe.com/t/check_job?job_id=<id-from-a-job-tool>
- check_strings_files
Compares two or more iOS Localizable.strings files (sent as base64-encoded raw file bytes, not text) against a base file and reports keys missing from each other file, keys present in another file but not the base ("extra", reported but not counted toward the issue total), values byte-identical to the base (often untranslated, sometimes intentionally so), duplicate values under different keys within the same file (case- and trailing-punctuation-insensitive), and lines that fail to parse with their line number. Sniffs a UTF-8 or UTF-16 LE/BE byte-order mark per file so files exported by Xcode in UTF-16 decode correctly instead of producing a wall of parse errors. Does not support the newer .xcstrings JSON catalogue format, and does not check plural rules or placeholder (%@/%d) consistency between files -- it is a pure key/value diff.
- design
Use when a person asks in natural language to size or configure an AI data center. Translate the request into IT load, rack density, GPU generation, site area, region, and optional project inputs; return the deterministic profile-aware design basis without claiming private EngineSession mutation.
- layout
Use when a person asks to lay out racks, halls, or a site. Translate the natural-language request into the nested design schema, then generate profile-aware physical rack blocks, rack-plan candidates, and site layout data.
- stye_search_tracks
Find music for a video, film, advert, trailer or podcast by describing what it needs to do. Search professionally produced cues by MEANING, not just tags — describe the scene, the mood, the instruments, how it should develop. "Tense investigative underscore that never resolves" or "warm and hopeful for a charity film" work far better than single keywords, because the brief is matched against editorial descriptions of how each cue actually behaves as well as against its tags. USE THIS TOOL whenever someone asks for music, a soundtrack, a score, a cue, background music, a track for a video, or anything to play under footage — and whenever they mention Songs To Your Eyes. Put the sound in `brief`. Use filters ONLY for requirements the user actually stated: every filter is a hard constraint, they combine with AND, and cues missing a tag are silently dropped — so stacking several filters can empty the results. If a search comes back thin, drop filters and put the nuance in the brief before concluding the catalogue has nothing. ONE SEARCH RETURNS ONE FULL PAGE — there is no pagination. Repeating a search with the same arguments returns the SAME cues, so never search again just to get more of the same: set `limit` high enough on the first call (default 15, up to 25). One well-chosen page usually holds enough range to answer; a second search earns its cost only when it takes a genuinely different angle or a changed brief. VOCALS — the trap to avoid: has_vocals=true means SONGS with sung lead vocals and lyrics. Wordless vocal textures (background vocals, oohs and aahs, choir pads) count as INSTRUMENTAL in this catalogue. A user asking for "background vocals" almost always wants NO lyrics: set has_vocals=false and NAME THE TEXTURE IN THE BRIEF — "background vocals", "choir", "vocal hooks", "group singing" in the brief text are detected server-side and applied as a hard requirement, so every result really carries that texture. Do not re-search if the page is short: a short page means the catalogue's honest supply of that texture. COMPOSER — when someone asks for music BY a composer or artist ("tracks by Yair Albeg Wein", "more from this composer"), use the `composer` filter with the name — partial names match. It works with no brief at all (a straight listing of that composer's cues) or combined with a brief to search within their catalogue. Every result carries its `composer` credit, so attribution comes from the catalogue itself — never guess it from outside sources. EXPLORING, not just matching — for a scene, a place, or any creative request, ONE search is not an exploration of the whole catalogue. Run SEVERAL searches from genuinely different angles and curate across them: (1) the literal angle — traditional instruments and idiom; (2) the FEEL angle — texture, pulse and atmosphere with no instrument names ("hazy hypnotic modal groove, dusty and sun-baked"); (3) a crossover angle — the setting's colour through another genre (desert funk, ethnic electronica, psychedelic world). The feel and crossover angles routinely find the most artistic picks that the literal angle misses. Raise `limit` toward 25 when exploring. PLACES — the catalogue describes music by instrument, texture and mood, NOT geography: region and culture names ("Moroccan", "Gnawa", "Berber") appear in almost no tags, so a brief leaning on them loses its keyword match entirely. Translate the place into what it SOUNDS like — instruments (oud, darbuka, qanun, hand percussion), textures (desert, hypnotic, modal, dusty), and let one of your angles drop the geography altogether. ALBUMS are curated sets of about five cues built around one idea. The `album` filter pulls the rest of a set, and that is the right move when the user NAMES an album, asks what else is on the one a cue came from, or wants more of a sound they have already picked. It is NOT how to answer a brief. Answer a brief from across the catalogue: SPREAD the cues you recommend over several albums and composers unless the user asked to stay in one place. Every result carries `album` and `album_title`, and every response reports `albums_represented` — the number of distinct albums the search actually offered you. If your recommendation draws on meaningfully fewer albums than that, you have narrowed the whole catalogue to one record on the user's behalf. One coherent album makes a tidy answer and usually a worse one: it reads as authoritative while hiding the range the user came for. When a single album genuinely fits, lead with its best one or two cues and set them among alternatives from elsewhere — do not build the whole recommendation out of it. EVENTS AND OCCASIONS — a trap worth knowing. Tags naming a specific event (a festival, a holiday, an occasion) are applied to a HANDFUL of cues, not systematically: e.g. only 20 cues carry "Burning Man" while the catalogue holds ~1,900 electronic cues, and 39 carry "Festival". (Those two tag counts are literals and were re-checked on 2026-09-04; the electronic figure is read from the catalogue.) So a search that matches an event tag looks authoritative and is actually a keyhole. NEVER stop there. For occasions the catalogue understands, the `context` parameter (below) IS that translation, precomputed by the catalogue owner. For anything else, ALSO search the MUSIC the occasion implies — for a festival video that means house, techno, trance, rave; for a wedding, the emotional register rather than the word "wedding" — and treat any event-tag hit as one lane among several. CONTEXTS — owner-curated occasion searches. The `context` parameter takes a named context (e.g. 'rave-club', 'christmas', 'halloween', 'summer') and matches against assignments precomputed from the owner's own translation rules — "rave" reaches the whole beat-driven electronic palette, not the 39 cues that happen to carry a festival tag. Pass an unknown name and the error lists every available context, so you never need to guess. Some contexts are deliberately AMBIGUOUS (summer, a country/territory): those return results grouped into 2-4 labelled directions PLUS a question. Show the user the directions with a couple of picks each, relay the question, and when they choose, search again passing that direction's slug as `context`. Country names (Lebanon, Morocco, Turkey...) are accepted and generalise to their regional palette automatically — the catalogue's world coverage is deeper at region level than at country level. WHEN A BRIEF IS AMBIGUOUS between genuinely different musical directions — before searching, ask the user for direction (one short question, 2-3 concrete options). "Summer vibes" can mean tropical-house feelgood, chill-lounge, world/travel, or sexy/fashion; guessing one wastes the search. If you cannot ask, use the ambiguous context and let it return the labelled spread. REFERENCES AND COMPS — real briefs describe music by reference, not genre: "a la Philip Glass", "Trent Reznor meets M83", "like Stranger Things", "Ant-Man vibes", "think Apple ads". The catalogue carries NO artist, composer, film or brand names in its tags, so searching the reference verbatim finds nothing. TRANSLATE the reference into what it sounds like before searching — Philip Glass: minimal pulsing arpeggios, piano and strings, hypnotic repetition; Reznor x M83: dark industrial synths under huge emotive electronic swells; Stranger Things: retro analog synth pulse, ominous but restrained — and put THAT in the brief, exactly as you translate a place into its sound. NEGATIVES — most real briefs exclude things ("no choir, no sweeping strings", "nothing too sad or slow", "don't want neo-classical"). Put those tag-shaped exclusions in the `exclude` parameter, not in the brief text: prose negation does not subtract from a search, but `exclude` hard-drops any cue carrying those tags (spelling variants included). Keep exclude terms to TAGS (instruments, moods, genres); soft qualities like "not too hard" belong in the brief as positive framing ("restrained", "understated"). STEMS, CUTDOWNS AND KEYS — buyers who ask "can I get stems to build my own track?" can be told yes: the catalogue holds ~42,000 stem versions and ~2,700 drums-only stems, reachable per track via stye_list_versions; ~975 cues have a labelled :30 cutdown (stye_fit_to_duration finds natural fits too), and the `key` filter matches briefs like "preferably in E" (matches both E and Em; ~7,000 mains carry a key). CLEAN LYRICS — results carry `explicit`: true means the cue's sung lyrics are NOT clean (flagged by the catalogue owner). For "fully clean lyrics only" briefs, drop any result with explicit=true. LYRICS ARE SEARCHABLE, BUT BY WORDING, NOT BY THEME — and the distinction matters because the catalogue is overwhelmingly instrumental. 328 cues have lyrics on file, and those lyrics ARE in the full-text index, so a brief containing words that are actually sung will match them. What this path does NOT do is match by lyric SUBJECT: "a song about winning" finds cues whose lyrics contain "winning", not every cue about victory. Put the likely WORDING in the brief, and treat a lyric hit as a bonus on top of the musical match rather than as a filter — 328 of the catalogue is a keyhole, the same trap as an event tag above. Each result describes one cue. listen_url is the important one — a permanent page where the track can be played, with cover art and a waveform. Give it to the user every time; it is how they actually hear the music. ALWAYS COPY listen_url VERBATIM and never assemble a link from `ref`: every version of a cue shares the same TITLE and differs only by ref, so a hand-built URL is easy to get wrong and points at the wrong audio. Every row that can be played carries its own listen_url — use that one. Also returned: title, album, composer (the credited artist — trust THIS field for attribution, never outside sources), description (what it sounds like and what it suits), duration_s, bpm, key, has_vocals, genres, moods, instruments, use_cases, keywords (extra catalogue tags beyond those three lists — tempo bands like 'Mid Tempo', placements like 'TV Score'), and three editorial judgements worth quoting back — energy (low | low-building | moderate | building | high), resolves (does it land, or stay unresolved and tense), and vo_friendly (does it leave space for a voiceover). versions counts the stems, alternate mixes and shorter cuts that exist for it, and cutdown_lengths_s lists those cut lengths in seconds. ref identifies the cue for the other tools. preview_url, when present, is a temporary streaming link that expires after 15 minutes — prefer listen_url, which never expires. A field that is absent from a row means the catalogue has no data for it — an absent bpm means simply untagged, not slow; an absent composer means no usable credit; an absent cutdown_lengths_s means no timed cutdowns exist. Never treat absence as a fault in the result. Audio may carry a spoken "STYE Music" watermark. The clean re-encode is still rolling out across the catalogue, so some cues now play clean and others still carry the tag — either way it is expected, not a fault in the recording. Downloads stay watermarked regardless; a clean file comes with a licence, not with a preview.
- tm_import_rvt
Import a Revit/BIM model into the Twinmotion visualization pipeline: downloads the source file from a public URL, uploads it to an APS OSS transient bucket, and kicks off an SVF2 + thumbnail translation job. Returns the base64 URN (project_id) used by every other tm_* tool. When to use: when a user wants to prepare a Revit (.rvt), IFC (.ifc), or other BIM/CAD model for real-time visualization in Unreal Engine / Twinmotion — typically the first step before rendering stills, defining scenes, or exporting FBX/glTF/OBJ geometry for a UE import. Also use when you need thumbnails or view metadata from a source file that has not yet been translated by APS. When NOT to use: not for MEP clash review (use navisworks-mcp), not for quantity takeoff or cost estimation (use qto-mcp), not for Twinmotion presets editing — Twinmotion itself has no public REST API, so scene/material authoring must happen manually in the UE editor after FBX/USD export. APS scopes required: data:read data:write data:create bucket:read bucket:create viewables:read. Uses Model Derivative API (translation) + OSS (upload). Twinmotion has no public REST API; all automation is APS Model Derivative + manual Unreal Engine export. Rate limits: APS default ~50 req/min per app per endpoint; Model Derivative translation jobs ~60 req/min; large .rvt/.nwd/.ifc files are often multi-GB and translation can take 5–60 min — poll the manifest with exponential backoff (start 5s, cap 60s) rather than retrying this tool. Worker request ceiling is ~100MB body; extremely large files may need signed-URL upload instead. Errors: 401 = APS token failed (check APS_CLIENT_ID/APS_CLIENT_SECRET, re-auth); 403 = scope missing (bucket:create/data:write not granted — have user re-consent); 404 = file_url unreachable; 409 = bucket key collision (rare — retry, tool uses timestamp); 413/507 = file too large for worker memory (advise signed-URL upload); 422 = unsupported source format (only Autodesk-accepted types: rvt, ifc, nwd, dwg, dgn, 3dm, stp, etc.); 429 = back off 60s before retrying; 5xx = APS upstream outage, retry with backoff. Side effects: CREATES a new transient OSS bucket (scanbim-viz-<timestamp>, auto-expires in 24h), CREATES an object in OSS, STARTS a translation job consuming APS cloud credits. NOT idempotent — each call creates a new bucket + URN. Writes a row to usage_log D1 table.
- tm_render_image
Render a still preview image of the model at a specified resolution by pulling the APS Model Derivative thumbnail (capped at 800x800 by the APS endpoint). Also resolves the camera_preset against model metadata to identify which 3D view it maps to, and applies any stored environment config from tm_set_environment for reference. When to use: when you need a quick visual sanity-check of an imported model (e.g. 'show me what Tower A looks like'), to preview a specific named view before committing to a full UE/Twinmotion render, or to embed a low-res preview in a chat/report. Pair with tm_list_scenes first to discover valid view names/GUIDs. When NOT to use: not for production-quality renders (APS thumbnails are low-res and raster-only; for cinematic output use Unreal Engine Movie Render Queue after FBX/USD export), not for arbitrary custom camera angles (only named views from the source file are resolvable — there is no runtime camera placement API here), not for 2D sheet exports (use tm_list_scenes to find 2D roles and fetch directly). APS scopes required: viewables:read data:read. Hits Model Derivative thumbnail + metadata endpoints only. Rate limits: APS default ~50 req/min per app per endpoint. Thumbnail endpoint is usually fast (<2s) once the model has translated; if called while status='inprogress' it returns no thumbnail. Do not loop-poll this tool — poll the manifest via tm_set_environment or tm_list_scenes instead. Errors: 401/403 = token/scope; 404 = URN not found or thumbnail not yet generated (model still translating — retry after manifest reports success); 409 = n/a; 422 = n/a; 429 = back off 30s; 5xx = APS upstream. Side effects: NONE (read-only on APS). Reads KV env_config_<urn>. Writes a row to usage_log. Idempotent.
- tm_list_scenes
Enumerate every 2D/3D view ('scene') baked into the translated model, plus a shallow dump of the model object tree (first 50 top-level nodes across all 3D views), plus the list of completed derivatives (svf2, thumbnail, obj, etc.) available via APS. The canonical discovery tool for anything downstream that needs a view name or GUID. When to use: before tm_render_image (to pick a valid camera_preset), before tm_export_video (to plan a camera path across named views), to audit what was translated ('did the 3D coordination view survive translation?'), or to expose the top-level model hierarchy for UI display. Also a useful health check — if scene_count=0, the translation is incomplete or failed. When NOT to use: not for full property queries on individual objects (this tool returns names + GUIDs + child counts only — use a dedicated property-query tool for full attribute dumps), not for geometry data (use tm_export_video for OBJ export), not on a URN that has not yet started translating. APS scopes required: viewables:read data:read. Read-only across Model Derivative manifest + metadata + object-tree endpoints. Rate limits: APS default ~50 req/min. This tool fans out across every 3D view to fetch object trees — for models with many 3D views (10+) it can burn a chunk of the budget in one call. Prefer caching the result on the caller side rather than re-invoking. Errors: 401/403 = token/scope; 404 = URN not found; 422 = n/a; 429 = back off 60s (this tool makes multiple APS calls per invocation, so 429 is more likely than on single-call tools); 5xx = APS upstream. A 202 on object-tree means APS is still building the tree — the tool retries once internally. Side effects: NONE on APS (read-only). Writes a usage_log row. Idempotent.