{"slug":"terminal","title":"terminal","summary":"The agent terminal -- its commands, absolute paths, how `search` actually matches, the `|` Twig pipeline, and /tmp as a compute surface. Load it before your first search comes back empty.","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-10-16T16:27:58.153578Z","repo":{"url":"https://github.com/jstanden/cerb","stars":84,"forks":38,"license":null,"updatedAt":"2026-10-16T15:09:59Z"},"bodyHtml":"<hr>\n<h2>name: terminal\ndescription: The agent terminal -- its commands, absolute paths, how <code>search</code> actually matches, the <code>|</code> Twig pipeline, and /tmp as a compute surface. Load it before your first search comes back empty.</h2>\n<h1>The agent terminal</h1>\n<p>Your terminal tool runs ONE command line per call -- verb, arguments, and flags together, exactly as you would type them at a prompt. Everything below is a COMMAND, not a tool of its own: there is no separate <code>search</code> tool, only <code>search ...</code> typed into the terminal.</p>\n<p>It is NOT a Unix shell. It has only the documented commands -- <code>ls</code>, <code>find</code>, <code>search</code>, <code>read</code>, <code>write</code>, <code>append</code>, <code>edit</code>, <code>copy</code>, <code>rm</code> -- plus a trailing <code>|</code> pipeline. A few Unix names work as aliases -- <code>cat</code> (read), <code>grep</code> (search), <code>dir</code> (ls), <code>cp</code> (copy) -- and everything else errors, <code>echo</code> and <code>awk</code> included.</p>\n<p><code>search</code> needs a fulltext index, which only a mounted volume has. With nothing but <code>/tmp</code> you do not have it -- filter <code>/tmp</code> with a pipeline instead.</p>\n<h2>Paths</h2>\n<p>Write every path in full. <code>cd</code> exists, but assume it does not stick: your terminal call starts at <code>/</code> every time, so a <code>cd</code> is gone by your next call. Use an absolute path (<code>/cerb-docs/references/docs/kata.md</code>) or the <code>@&lt;filesystem&gt;/path</code> shorthand (<code>@cerb-docs/references/docs/kata.md</code>). A mount is read-only unless its overview says otherwise; <code>/tmp</code> is always read-write.</p>\n<h2>Searching the mounted filesystems</h2>\n<p>The <code>search</code> command matches file CONTENTS with AND, not OR -- every word in the query must appear in the same file. Piling on keywords narrows to zero hits fast, and zero hits is NOT evidence the topic is undocumented.</p>\n<ul>\n<li>Start with the one or two most distinctive terms, then narrow with <code>--path</code> or <code>--ext</code> instead of adding more words.</li>\n<li><strong><code>--terms</code> is the OR view, and it is how you find the right word.</strong> It counts how many files contain EACH word, ranked, instead of searching for all of them: <code>search --terms school college academic university tuition</code>. One call, any number of synonyms, no reading. Take the highest count, require it with <code>+</code>, and throw the next set of words at it: <code>search --terms +college tuition fees pricing</code>. Repeat until the word list is good, THEN run the real <code>search</code>.</li>\n<li><strong>A wildcard or stem term lists the words it covers</strong>, inline on one indented line beneath it: <code>auto*</code> reports <code>automations (476) automation (374) automatically (228) ...</code>. That is how you learn the vocabulary this corpus actually uses instead of guessing at it; a trailing <code>...</code> means the list was capped.</li>\n<li>A <code>+</code> term is echoed as a heading above the counts; every count below it is <em>within</em> the files that contain it, so numbers collapse fast. That collapse is the signal -- keep the words that survive it.</li>\n<li>A miss falls back to this view automatically, and keeps any <code>+</code> you already had, so a failed AND search still tells you which words exist alongside it.</li>\n<li>A <code>-</code> instead of a count means the index skips that word as too common (<code>the</code>, <code>not</code>, <code>can</code>, <code>com</code>, <code>www</code>, ...) -- it was never searched for, which is not the same as finding nothing.</li>\n<li>Run separate searches for alternatives; there is no OR.</li>\n<li><strong>A search returns the 25 most relevant files, not every match.</strong> <code>--top &lt;n&gt;</code> raises or lowers that cap and <code>--top 0</code> returns every match unranked, so a full list is one flag away. Don't report a capped list as the whole answer.</li>\n<li>Use <code>find</code> to match names and <code>search</code> to match contents. Add <code>--lines</code> only after you've picked a file worth reading in context.</li>\n<li><strong><code>find</code> also carries every Markdown file's frontmatter, so you can select on metadata without opening anything.</strong> Each row has its keys under <code>meta</code>, and <code>--fields title,description</code> prints chosen ones as columns: <code>find *.md --fields name | files|filter(f =&gt; f.meta.name starts with \"cerb\")</code>. Listing never opens a file, so this costs nothing.</li>\n<li>Prefer <code>search</code>/<code>find</code> to locate a file, then <code>read</code> only the part you need (<code>--offset</code>/<code>--limit</code>).</li>\n</ul>\n<h2>/tmp -- a compute surface, not an overflow buffer</h2>\n<p><code>/tmp</code> is a read-write scratch area. Reach for it whenever you'd otherwise scan a long piece of text by hand, or need to hold intermediate work across steps.</p>\n<ul>\n<li>Write an arbitrary string to a file (<code>write /tmp/scratch.txt</code>), then read it back through a trailing Twig filter chain to count, filter, reshape, or diff it -- for example staging alternate drafts, or reducing a large document to just the lines that matter, before committing a final version anywhere.</li>\n<li>It is per-session, and it is NOT indexed by <code>search</code>. Filter it with a pipeline rather than searching it.</li>\n<li>A command whose output is too large to return is saved there and referenced by path.</li>\n</ul>\n<h2>The <code>|</code> pipeline</h2>\n<p>Pipe ANY command through Twig filters with a trailing <code>|</code> (<code>lines</code>, <code>filter</code>, <code>map</code>, <code>length</code>, <code>column</code>, ...). The pipeline runs on the FULL output before any truncation, so it is how you reduce a big result to just what you need instead of paying for the whole thing in context.</p>\n<pre><code>read /tmp/scratch.txt | lines|filter(l =&gt; \"field\" in l)\nsearch widgets | results|map(r =&gt; r.meta.title ?? r.path)\nls /docs | files|filter(f =&gt; not f.is_dir)|column(\"name\")\n</code></pre>\n<p><code>lines</code> preserves original line indices as keys. Each command sets its own row variable -- <code>lines</code>, <code>results</code>, <code>files</code> above -- and that is what makes a pipe iterate ROWS rather than text. For a longer transform than fits on one line, put a Twig template in <code>script</code> instead of a trailing <code>|</code>.</p>\n<p><strong>This is Cerb scripting, not a pipeline language of its own</strong> -- the same Twig, the same filters, functions and operators you would write anywhere else in Cerb. Read <code>@cerb-agents/skills/scripting/SKILL.md</code> for what is available rather than guessing at a filter name here.</p>\n<h2><code>cerb</code> -- the command line into this installation</h2>\n<p>Some agents also have <code>cerb</code>, a command line into THIS Cerb install rather than into files. It reports what this installation actually has, custom record types and fieldsets included, which the documentation cannot. Run <code>cerb help</code> to see what it answers, and <code>cerb &lt;topic&gt; help</code> for one topic's usage. Its rows pipe like any other command's.</p>\n","files":[{"path":"SKILL.md","sizeBytes":6099,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-10-16T16:28:17.666618Z","sha256":"CEAD002EAC7738E97A51038763ACD218072EA838C8AFD8A7CE12B000C198ED35","sizeBytes":2945},"review":null,"source":{"repositoryUrl":"https://github.com/jstanden/cerb","path":"features/cerberusweb.core/assets/agent_filesystems/cerb-agents/skills/terminal","license":null,"commit":"cf28b62ee0f67ff993645931568a4e4bbad074f0","subtreeSha":"0E72B0EAE84896104A56E2FF3B30146212224FCA8D303C8C80B8F68B1C81B41F","lastSyncedAt":"2026-10-16T16:27:56.786317Z"},"reviewedAt":"2026-10-16T16:29:03.084829Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/jstanden/cerb/tree/12.0.x/features/cerberusweb.core/assets/agent_filesystems/cerb-agents/skills/terminal"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install jstanden-cerb@llmmart"},{"target":"git","command":"git clone https://github.com/jstanden/cerb.git"}]}