---
title: "Build a Git Insights Extension"
source: https://docs.autohand.ai/tutorials/extensions/git-insights-extension
---

# Build the Git Insights extension

Package two read-only Git evidence tools in one extension and verify deterministic registration, bounded parameters, project scope, and truthful permission behavior.

## Pattern under test

`autohand.git-insights` contributes tools only. It proves that a manifest can declare multiple contributions and that registration does not depend on filesystem enumeration order.

``` text
autohand.git-insights/
  autohand.extension.json
  README.md
  tools/recent-history.json
  tools/changed-files.json
```

## Create the manifest

``` json
{
  "$schema": "https://raw.githubusercontent.com/autohandai/code-extensions/main/schema/autohand.extension.schema.json",
  "schemaVersion": 1,
  "extensionApi": 1,
  "id": "autohand.git-insights",
  "name": "Git Insights",
  "version": "1.0.0",
  "description": "Inspect recent history and changed files with reusable Git tools.",
  "license": "Apache-2.0",
  "repository": "https://github.com/autohandai/code-extensions",
  "contributes": {
    "tools": ["tools/recent-history.json", "tools/changed-files.json"]
  }
}
```

The declared order is clear to readers, but runtime identity is the tool name. Every package and contribution is processed deterministically, and duplicate contribution paths or names are rejected.

## Add bounded recent history

``` json
{
  "name": "recent_history",
  "description": "Show a bounded number of recent commits",
  "parameters": {
    "type": "object",
    "properties": {
      "count": {
        "type": "number",
        "description": "Maximum number of commits"
      }
    },
    "required": ["count"]
  },
  "handler": "git log --max-count={{count}} --oneline",
  "source": "user"
}
```

Bounding output is part of tool design. The parameter schema requires a number, while the fixed `--max-count` option keeps the command's purpose stable.

## Add changed-file evidence

``` json
{
  "name": "changed_files_since",
  "description": "List files changed between a base revision and HEAD",
  "parameters": {
    "type": "object",
    "properties": {
      "base": {
        "type": "string",
        "description": "Base branch, tag, or commit"
      }
    },
    "required": ["base"]
  },
  "handler": "git diff --name-only {{base}}...HEAD",
  "source": "user"
}
```

Three-dot diff semantics compare the merge base of `base` and `HEAD` to `HEAD`. Document this because two-dot and three-dot ranges answer different questions.

## Install into a repository

``` bash
autohand --path /work/sample extensions validate ./autohand.git-insights
autohand --path /work/sample extensions install ./autohand.git-insights --scope project
autohand --path /work/sample extensions show autohand.git-insights --scope project --json
autohand --path /work/sample extensions doctor
```

The JSON report should contain exactly `recent_history` and `changed_files_since`, no agents, project scope, enabled state, and copied installation.

## Exercise both tools

Use a repository with at least three commits and a feature branch that diverges from `main`. Ask:

``` text
Use recent_history with count 3. Then use changed_files_since with base main.
Explain which commits and files are part of this branch. Do not modify the repo.
```

Confirm that output is limited, revision errors are returned truthfully, and a read-only description does not imply automatic approval. Permission policy and hooks still apply.

## Test deterministic conflict handling

1.  Create a second fixture extension that also declares `recent_history`.
2.  Validate both packages independently.
3.  Install the real package, then attempt to install the conflicting fixture.
4.  Confirm installation fails with the existing owner id rather than selecting whichever directory was read first.
5.  Run `doctor` and confirm the active package remains healthy.

## Remove the package

``` bash
autohand --path /work/sample extensions remove autohand.git-insights --scope project --yes
autohand --path /work/sample extensions list --scope project
autohand --path /work/sample extensions doctor
```

Neither tool should remain in a fresh session. Any unrelated extension in the same project root must remain installed and active.