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.
The shell command to execute. Runs in the project directory.
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
Run tests
Check format
Build project with timeout
Run custom scripts
Check dependencies
{ :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.
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
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.
Show staged changes (equivalent to git diff --cached)
Limit diff to specific file
Unstaged changes
Staged changes
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.
Files to stage before committing (optional)
Commit staged changes
Stage and commit
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.
Number of commits to show
args.format
string
default: "%h %s (%an, %ar)"
Git log format string. Uses git’s --format syntax.
Recent commits (default)
Custom count
Custom format
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.
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).
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.
Stash action: push, pop, or list
Stash changes
Pop stash
List stashes
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
Check status and commit
Review before committing
Stash workflow
# 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.