Skip to content
ivralo
Sections

Docs / Developer mode

Git

ivralo reads git's record with tools of its own, writes to it only through calls that ask, and pushes exactly one kind of branch: the one it made, for a draft pull request. This page covers the read tools, the write tools and how each may run unattended, the one push, and finding a regression with ivralo bisect.

Who holds what

GrantToolsHeld by
code.readThe git reads belowThe main agent, the Code Engineer, the Incident Investigator
git.commitThe git writes belowThe main agent and the Code Engineer, in a repository; never an instance
git.pushopen_pull_requestThe main agent and the Code Engineer, once the ivralo home holds ivralo's own git identity; never an instance

The strict profile drops git.commit and git.push. Every tool needs a .git at the workspace root.

The tree line

Every git answer starts with one line about the tree, because a dirty tree changes what a diff or a history means:

tree: clean on main at a1b2c3d (origin/main: 2 ahead, as of the last fetch)
tree: dirty on main at a1b2c3d - 2 modified, 1 staged, 3 untracked
tree: dirty, detached at 9f8e7d6 - 1 conflicted; a merge is in progress

"As of the last fetch" is literal: ivralo never fetches. .ivralo/, .git/ and every .env file are left out of every listing, diff, patch and blame, and the answer says how many it left out.

The reads

Reads ask nobody and run nothing but git: never a diff program or filter your repository configured, and never with a lock on your index.

ToolAnswers
git_statusFiles that differ from HEAD, by group: conflicted, staged, modified, untracked
git_diff(path, against, context)What is not staged, or the tree against a commit: a +/- table first, then the patches
git_diff_cached(path, context)What a commit would take
git_changed_files(base, head)Every uncommitted file, or the files a branch changed since its merge base
git_log(limit, path, revision, author, since, grep, term)Commits newest first; term= finds commits that added or removed a string
git_log_file(path, limit)One file's commits across renames
git_blame(path, start, end)Runs of lines from one commit, whitespace and moves looked through; 200 lines a call
git_show_commit(commit, path)A commit whole: message, table, patches
git_branch_info()The branch, its upstream, local branches, an operation in progress
git_compare_branches(base, head)The merge base, the commits only on each side, the files changed
git_merge_conflict_info(path)A merge, rebase, cherry-pick or revert in progress, and each conflicted file's regions

Four more answer "why is the code like this" with git's facts, never a judgement:

ToolAnswers
git_log_symbol(symbol)The commits that changed one function's lines, followed back with git log -L
git_reason_about_change(path, start, end)The commit that introduced those lines with its whole message, and what changed them since; term= finds when a string was added and removed
git_related_commits(commit)Commits git's own wording links to it (a revert, a cherry-pick, a fixup!), then nearby commits on its files
git_risk_score(path)Per file over the last thousand commits: commits, recent ones, fixes, authors, co-changed files, with the formula printed

The writes

Seven tools carry git.commit:

ToolDoesRuns as
git_generate_commit_messageProposes a message for what is staged, in your log's style; writes nothing, asks nothing
git_create_branch(name)A branch at HEAD, switched togit switch -c
git_stage_files(paths)Stages files by path, never a .envgit add
git_unstage_files(paths)Unstages filesgit restore --staged
git_commit(message)Commits what is staged, with your hooks, identity and signing; never amendsgit commit
git_revert_commit(commit)A new commit that undoes one; a conflict is aborted and nothing changesgit revert
git_restore_file(path, source)A file put back as in a commit, its current version kept in ivralo's history firstgit restore

The six that change something show you the call first, like an edit (Editing and approvals). a covers the rest of the turn and /confirm the session. Each is refused before git runs:

  • while a changeset is open, because its edits are in the staged tree until it lands;
  • in a folder you have not trusted, because a commit runs the repository's hooks;
  • in an unattended run, unless one of the three ways below allows it.

Letting a write run unattended

WayExample
Name the tool under allow_tools in a permissions.json"allow_tools": ["git_stage_files", "git_commit"]
Allow the git command it runs, as you would for run_shell"allow": ["git add", "git commit", "git switch -c"]
Server mode: IVRALO_MODE=server grants git.commit and git.push unattendedwritten by ivralo init --server

Each write is judged as the shell command it runs, so a deny entry for that command refuses the tool, attended or not, and the dialog's p stores the command's leading words like it does for a shell command. An entry matches the command as the tool spells it (git add -- <paths>), so the entry is git add, not git add .env. An open changeset and an untrusted folder still refuse, whatever allow says.

There is no tool that fetches, pulls, amends, resets, rebases or deletes a branch, and the shell denies the commands that rewrite history (Shell commands).

On a server install, ivralo init --server writes a git identity of ivralo's own to the home's gitconfig, and git_commit and git_revert_commit use it as author and committer. Your repository's and your global configuration are untouched. Without that file, a commit is yours.

The one push

open_pull_request(branch, title, summary, incident) pushes a branch to origin and opens a draft pull request for it. It asks on every call, and nothing lifts that; with nobody to ask it runs only in server mode. It refuses, saying why, before anything leaves the machine:

  • a name that forces (+branch) or is an option;
  • the remote's default branch, and main whatever the remote says;
  • a branch the remote already has: ivralo creates a branch there, it never updates one;
  • any commit it would send that this ivralo process did not make with git_commit in this session, under its own identity, checked against the remote's real heads;
  • a commit that changes a hook, or uncommitted changes under the hooks;
  • an origin that is not https on the one forge (github.com, or the host of IVRALO_GITHUB_URL), or a forge host the egress policy refuses;
  • no forge credential, or a folder you have not trusted.

The token reaches git through one inline credential helper for the forge's host alone, and nothing is stored. It sends no tag and no submodule, and never forces.

ivralo never merges. The shell denies every git push, gh pr merge, gh pr ready and any gh api call naming a merge or ready, whatever permissions.json says. No grant, tool or command merges, approves, enables auto-merge or marks a draft ready. The merge is a person's act on the forge. Draft pull requests covers the server setup.

Finding the commit that broke something

ivralo bisect searches for the first commit where a command fails. The agents do the same with git_find_regression_commit. Either way it runs as a job, never inside a turn and never in your checkout.

ivralo bisect --good v1.2
ivralo bisect --good v1.2 --bad HEAD --command "./scripts/check.sh" --steps 30
FlagDefaultMeaning
--goodrequiredA commit where the command passes
--badHEADA commit where it fails
--commandthe declared test commandWhat to run at each commit
--stepsIVRALO_BISECT_STEPS (20)The most commands one search runs

The job checks out each commit in a worktree of its own under the home, runs the command there and reads its exit code as git bisect run does: 0 good, 125 skip, anything else bad. It runs the command at bad and good first; if it does not fail at one and pass at the other, there is nothing to search. Each step is bounded by IVRALO_BISECT_STEP_TIMEOUT (900 seconds). Every verdict is written on the job, so ivralo job <id> shows them and an interrupted job continues from them with ivralo resume <id>. It ends with the first bad commit and its message, or with the few commits it narrowed to. Your branch, index, refs and files are never touched.