Skip to main content
Loom provides tools for executing shell commands and performing git operations, enabling agents to run tests, build projects, and manage version control.

shell

Executes shell commands in the project directory and returns stdout, stderr, and exit code.
command
string
required
The shell command to execute. Runs in the project directory.
timeout
integer
default:"30000"
Timeout in milliseconds. Commands that exceed this duration are terminated.

Returns

Success response (exit code 0):
Exit code: 0
mix test
....

Finished in 0.5 seconds
4 tests, 0 failures
Error response (non-zero exit code):
Exit code: 1
mix test
.F..

1) test creates user (MyApp.UserTest)
   ...
Both stdout and stderr are captured and combined in the output. The exit code determines success vs. error response.

Output Limits

Output is truncated at 10,000 characters. If the command produces more output:
Exit code: 0
[first 10,000 characters of output]
... (5432 characters truncated)

Execution Details

Commands always run in the project root directory. No need to cd before running commands.
Commands inherit the system environment. Mix, npm, cargo, and other tools work as expected.
Uses Erlang ports (not a sandboxed shell) to execute real system commands. This allows running build tools, test suites, and other native commands.

Usage Examples

{:ok, result} = Loom.Tools.Shell.run(
  %{command: "mix test"},
  %{project_path: "/home/user/project"}
)

Common Commands

Elixir

mix test
mix compile
mix format --check-formatted
mix deps.get
mix dialyzer

Node.js

npm test
npm run build
npm install
npm run lint

Rust

cargo test
cargo build --release
cargo clippy
cargo fmt -- --check

Python

pytest
python -m unittest
pip install -r requirements.txt
black --check .
Use shell for running tests and builds, but prefer specific tools like git for version control operations.

git

Performs git operations using the git_cli library. Provides structured access to common git commands.
operation
string
required
The git operation to perform. Supported operations:
  • status - View working tree status
  • diff - Show changes
  • commit - Create a commit
  • log - View commit history
  • add - Stage files
  • reset - Unstage files
  • stash - Stash changes
args
map
Operation-specific arguments (see below)

Operations

status

View the current git status.
{:ok, result} = Loom.Tools.Git.run(
  %{operation: "status"},
  context
)
Returns:
Git status:
 M lib/loom/router.ex
?? new_file.ex
Or if clean:
Working tree clean — no changes.

diff

Show changes between commits, working tree, and staging area.
args.staged
boolean
default:"false"
Show staged changes (equivalent to git diff --cached)
args.file
string
Limit diff to specific file
Loom.Tools.Git.run(
  %{operation: "diff"},
  context
)
Returns:
diff --git a/lib/loom/router.ex b/lib/loom/router.ex
index 1234567..abcdefg 100644
--- a/lib/loom/router.ex
+++ b/lib/loom/router.ex
@@ -10,6 +10,7 @@
   plug :match
+  plug :auth
   plug :dispatch

commit

Create a new commit. Optionally stage files before committing.
args.message
string
required
Commit message
args.files
list
Files to stage before committing (optional)
Loom.Tools.Git.run(
  %{
    operation: "commit",
    args: %{message: "Add authentication middleware"}
  },
  context
)
Returns:
Commit created:
[main 1234567] Add authentication middleware
 1 file changed, 5 insertions(+)

log

View commit history.
args.count
integer
default:"10"
Number of commits to show
args.format
string
default:"%h %s (%an, %ar)"
Git log format string. Uses git’s --format syntax.
Loom.Tools.Git.run(
  %{operation: "log"},
  context
)
Returns:
Recent commits:
1234567 Add authentication middleware (Alice, 2 hours ago)
abcdefg Fix user validation (Bob, 1 day ago)
9876543 Initial commit (Alice, 2 days ago)

add

Stage files for commit.
args.files
list
required
List of file paths to stage
Loom.Tools.Git.run(
  %{
    operation: "add",
    args: %{
      files: [
        "lib/my_app/router.ex",
        "test/my_app/router_test.exs"
      ]
    }
  },
  context
)
Returns:
Staged 2 file(s): lib/my_app/router.ex, test/my_app/router_test.exs

reset

Unstage files (soft reset only, never destructive).
args.files
list
required
List of file paths to unstage
Loom.Tools.Git.run(
  %{
    operation: "reset",
    args: %{
      files: ["lib/my_app/router.ex"]
    }
  },
  context
)
Returns:
Unstaged 1 file(s): lib/my_app/router.ex
This tool only supports soft reset (unstaging). Hard resets are not available for safety.

stash

Stash or retrieve changes.
args.action
string
default:"push"
Stash action: push, pop, or list
Loom.Tools.Git.run(
  %{
    operation: "stash",
    args: %{action: "push"}
  },
  context
)
Returns (push):
Stash pushed:
Saved working directory and index state WIP on main: 1234567 Add auth
Returns (list):
Stash list:
stash@{0}: WIP on main: 1234567 Add auth
stash@{1}: WIP on feature: abcdefg Update router

Error Handling

All git operations return descriptive errors:
Loom.Tools.Git.run(
  %{
    operation: "commit",
    args: %{message: "Fix bug"}
  },
  context
)

# If nothing is staged:
{:error, "git commit failed: nothing to commit, working tree clean"}

Workflow Examples

# 1. Check what changed
{:ok, status} = Git.run(%{operation: "status"}, ctx)

# 2. View the diff
{:ok, diff} = Git.run(%{operation: "diff"}, ctx)

# 3. Stage files
{:ok, _} = Git.run(
  %{operation: "add", args: %{files: ["lib/file.ex"]}},
  ctx
)

# 4. Commit
{:ok, _} = Git.run(
  %{operation: "commit", args: %{message: "Add feature"}},
  ctx
)

Implementation Details

Shell and git tools are implemented in lib/loom/tools/: The git tool uses the git_cli library for structured git operations.

Build docs developers (and LLMs) love