A safe, simple, extensible, and fast agent harness
ein book src using-ein tools.md
5.5 kB · 140 lines
Markdown
at main

Built-in Tools #

Ein ships with six tool plugins that give the agent the ability to execute shell commands, work with files, search file contents, and fetch pages from the web. Each tool call appears inline in the conversation pane as it runs.

How tool calls appear #

▸ Bash  ls -la src/
  total 40
  drwxr-xr-x  8 you  staff  256 May  6 11:30 .
  drwxr-xr-x  15 you staff  480 May  6 11:00 ..
  -rw-r--r--  1 you  staff  4096 May  6 10:45 main.rs

The ▸ ToolName indicator (steel blue) shows the tool name and its primary argument. Bash streams up to five lines beneath it and keeps them after the call finishes because its output is useful to the reader. Other tool results still reach the model without being drawn in full.

Filesystem tools are limited to the connection's workspace roots. Tool plugins can reach only the hosts permitted by the server's tool policy. See Security & Sandboxing.


Bash #

Executes a shell command and returns its output.

▸ Bash  cargo test --lib
  running 12 tests
  test config::tests::build_config_openrouter_default_base_url ... ok
  ...
  test result: ok. 12 passed; 0 failed

Streaming: Bash output is streamed live as the command runs, so you see progress in real time without waiting for completion.

Empty output: if the command produces no output, the display shows (no output).

The command parameter is passed as a shell string and executed via the host spawn syscall. Standard shell features (pipes, redirects, globbing) work as expected. Bash is not yet confined to the WASM filesystem sandbox; see the security guide before running an untrusted session.


Read #

Reads a file from the filesystem and returns its contents.

▸ Read  src/main.rs

The file content is sent to the model but is not displayed in full in the conversation pane (it would be too verbose). The tool call indicator shows the file path.

The file must be within one of the connection's workspace roots.


Grep #

Searches file contents by regular expression and returns the matching lines with their paths and line numbers.

▸ Grep  render_allowed_hosts
  eind/src/grpc.rs:1797:fn render_allowed_hosts(hosts: &[String]) -> String {
  eind/src/grpc.rs:1701:        sections.push(render_allowed_hosts(&cfg.allowed_hosts));

Reach for this before Read when you're looking for something rather than reading something — which file defines a name, everywhere a function is called, whether a string appears at all. Point path at the narrowest place the answer could be; searching a whole repository for a common word returns a capped page of matches from everywhere. It's also the better choice over Bash with grep/rg/find: no shell quoting to get wrong, and results come back capped and numbered.

.git, .jj, target, and node_modules are never searched, and binary or very large files are skipped. The searched path must be within one of the connection's workspace roots.


Write #

Writes content to a file, creating it if it doesn't exist or overwriting it if it does.

▸ Write  src/new_module.rs

The file path is shown in the indicator. The agent provides the full file contents; the write is atomic.

The target path must be within one of the connection's workspace roots.


Edit #

Replaces an exact string in a file with new content. More precise than Write for targeted changes.

▸ Edit  src/config.rs
  @@ -42,7 +42,7 @@
  -    let config_path = dirs::home_dir()
  -        .ok_or_else(|| anyhow::anyhow!("Cannot determine home directory"))?
  +    let config_path = dirs::home_dir()
  +        .ok_or_else(|| anyhow::anyhow!("Home directory not found"))?

The Edit tool renders a syntax-highlighted diff using the base16-ocean.dark theme. Up to 5 removed lines (red) and 5 added lines (green) are shown. For larger diffs the display is truncated but the full edit is applied.

The tool fails if the old_string is not found exactly in the file, or if it matches more than once. The agent handles retries.


WebFetch #

Fetches a URL over HTTP or HTTPS and returns its content: HTML is converted to readable markdown, plain text/JSON/XML come back verbatim, and anything else is refused by name rather than returned as raw bytes.

▸ WebFetch  https://docs.rs/tokio/latest/tokio/task/

The tool follows redirects itself and upgrades a plain http:// URL to https:// automatically. There is no session and no script execution: a page behind a login or a paywall, or one that JavaScript builds after the page loads, comes back as whatever this one request actually received, not what a browser would render.

Fetched text is marked as untrusted data in the result — it's content written by whoever controls that page, not instructions, and should be read that way regardless of what it says.

WebFetch can only reach hosts the eind operator has allowed under tool_policy.plugins.ein_webfetch.allowed_hosts. A client cannot widen that list. See Network access.


Skill #

Loads the instructions for one of your skills. Unlike the tool plugins above this one is built into the server rather than a WASM plugin, and it only appears when ~/.ein/skills holds at least one skill.

▸ Skill  commit-style

The indicator shows the skill name. See Skills for how to write one.