# Install Iliad MD (instructions for AI agents)

> You are an AI agent (Claude Code, Codex, or similar) and a person asked you to set up Iliad for them. Follow these steps in order. Every command is for macOS in zsh or bash. Run each fenced block **as one shell invocation in a fresh shell**, because later lines use variables set earlier in the same block.

Iliad MD is a free, open-source (MIT) Markdown writing app for macOS. The person writes in plain `.md` files in a folder on their disk. When an outside agent like you edits those files, Iliad shows every change inside the document so the person can **Keep** or **Restore** it, chunk by chunk. Iliad has no chat panel and no built-in agent. It ships an `iliad` command (`status`, `open`, `skill`) and a skill that tells agents like you how to work alongside it. Website https://iliad.md · Source https://github.com/brainforwarding/iliad

Setup installs the app to `/Applications/Iliad MD.app` (with Homebrew when the Mac has it, otherwise from the verified `.dmg`), links the `iliad` command onto `PATH`, installs the Iliad skill for Claude Code (or adds it to `AGENTS.md` for Codex and other agents), verifies, and ends with a short summary for the person.

## Rules

- **Ask before you install.** Say what you will do in one short message (install with Homebrew if they have it or download about 160 MB from GitHub, install to `/Applications`, link `iliad` and install the skill), then wait for a yes.
- **Never** disable Gatekeeper, run `spctl --master-disable`, strip quarantine with `xattr -d`, or use `sudo`. The app is signed and notarized by Apple, so none of that is needed.
- If a check fails, stop and tell the person what failed. Do not work around a failed integrity check.
- Do not write to the person's Markdown files, except an `AGENTS.md` they approve in step 4. Iliad keeps its settings in app data.

## 1. Preflight

```sh
sw_vers -productVersion                      # needs 12.0 or later (macOS 12 Monterey)
sysctl -n hw.optional.arm64 2>/dev/null      # needs 1 (Apple Silicon); uname -m can say x86_64 under Rosetta
for app in "/Applications/Iliad MD.app" "$HOME/Applications/Iliad MD.app"; do
  [ -d "$app" ] && echo "installed: $app $(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$app/Contents/Info.plist")"
done
curl -fsSL https://github.com/brainforwarding/iliad/releases/latest/download/latest-mac.yml | awk '/^version:/{print "latest: " $2}'
command -v iliad && iliad status; echo "status exit: $?"
command -v brew                              # Homebrew present? (optional)
```

Then decide what to do.

- **macOS older than 12 (Monterey), or `hw.optional.arm64` is not `1`.** Stop. There is no build for this Mac yet (no Intel, Windows or Linux build). Tell the person so.
- **Iliad is already installed (any version).** Do not reinstall or overwrite it. Skip step 2 and go to step 3, using that app path. If the installed version is older than the latest, tell the person to update from inside Iliad. They choose **Iliad MD → Check for Updates...** in the menu bar, or **Check for Updates...** in the folder menu at the top of the sidebar. Iliad then shows "Iliad MD <version> is available." with **Download** and **View Release**. Do not quit Iliad or replace the app yourself unless the person asks. See "Reinstall (only if asked)" below.
- **`iliad status` exit 3 (`Iliad is not open.`).** This is normal. The command works and the app just isn't running.
- **Iliad is not installed and `command -v brew` prints a path.** Prefer Homebrew (step 2a), after the person says yes.
- **Iliad is not installed and there is no Homebrew.** Use the `.dmg` (step 2b). Do not install Homebrew yourself.

## 2. Install the app

Run this step only when Iliad is not installed.

### 2a. With Homebrew (preferred when `brew` is available)

The cask installs `/Applications/Iliad MD.app` and links the `iliad` command into Homebrew's `bin`, which is already on `PATH`. Homebrew checks the download's SHA-256 and the cask requires macOS 12+ on Apple Silicon.

```sh
brew install --cask brainforwarding/tap/iliad-md
iliad --help                     # prints Usage:, exit 0
```

If both succeed, **skip step 2b and step 3** and go to step 4. If `iliad --help` fails with `command not found`, open a new shell or run `hash -r`, then check that `$(brew --prefix)/bin` is on `PATH`. If `brew install` itself fails, tell the person what it printed, and offer the `.dmg` path (2b) instead.

The person updates later with `brew upgrade --cask iliad-md` (or from inside Iliad, as above).

### 2b. Without Homebrew, download, verify and install the `.dmg`

It downloads the `.dmg` named in `latest-mac.yml`, or the stable `Iliad-MD-arm64.dmg` if that fails, checks it against the SHA-512 in `latest-mac.yml`, mounts it without opening Finder, copies the app into `/Applications`, and cleans up.

```sh
set -eu
base="https://github.com/brainforwarding/iliad/releases/latest/download"
app="/Applications/Iliad MD.app"
[ ! -e "$app" ] || { echo "Iliad is already installed; skip to step 3." >&2; exit 1; }
tmp="$(mktemp -d)"
curl -fsSL "$base/latest-mac.yml" -o "$tmp/latest-mac.yml"
version="$(awk '/^version:/{print $2}' "$tmp/latest-mac.yml")"
dmg="$(awk '$2=="url:" && $3 ~ /\.dmg$/ {print $3; exit}' "$tmp/latest-mac.yml")"
want="$(awk -v f="$dmg" '$2=="url:" && $3==f {getline; print $2; exit}' "$tmp/latest-mac.yml")"
echo "Downloading Iliad MD $version"
curl -fL --progress-bar "https://github.com/brainforwarding/iliad/releases/download/v$version/$dmg" -o "$tmp/$dmg" ||
  curl -fL --progress-bar "$base/Iliad-MD-arm64.dmg" -o "$tmp/$dmg"
got="$(openssl dgst -sha512 -binary "$tmp/$dmg" | base64)"
[ "$got" = "$want" ] || { echo "SHA-512 mismatch; not installing." >&2; exit 1; }
mkdir "$tmp/mnt"
hdiutil attach -nobrowse -readonly -noautoopen -mountpoint "$tmp/mnt" "$tmp/$dmg" >/dev/null
trap 'hdiutil detach "$tmp/mnt" -quiet 2>/dev/null || true' EXIT
[ -d "$tmp/mnt/Iliad MD.app" ] || { echo "Iliad MD.app not found in the disk image." >&2; ls "$tmp/mnt"; exit 1; }
codesign --verify --deep --strict "$tmp/mnt/Iliad MD.app"
ditto "$tmp/mnt/Iliad MD.app" "$app"
hdiutil detach "$tmp/mnt" -quiet
trap - EXIT
rm -rf "$tmp"
spctl --assess --type execute -vv "$app"      # expect: accepted, source=Notarized Developer ID
echo "Installed $app ($version)"
```

If `/Applications` is not writable (`Permission denied` from `ditto`), do not use `sudo`. Ask the person whether to install to `~/Applications` instead. Then set `app="$HOME/Applications/Iliad MD.app"`, run `mkdir -p "$HOME/Applications"` first, and use that same path in step 3.

## 3. Link the `iliad` command

Skip this step if you installed with Homebrew in step 2a. The cask already linked `iliad`.

Iliad 0.4.0 and later link the command themselves. Run the wrapper inside the app. It runs on the app's own runtime, so the person doesn't need Node.

```sh
app="/Applications/Iliad MD.app"               # or "$HOME/Applications/Iliad MD.app"
"$app/Contents/Resources/bin/iliad" install --json
```

It links `iliad` into the first usable folder of `/opt/homebrew/bin`, `/usr/local/bin`, `~/.local/bin`, never replaces an `iliad` that belongs to another tool, and is safe to rerun (`"action": "unchanged"`). Then read the JSON.

- `"ok": true` means it worked. Use `linkPath` (the absolute path of the new command) for the next steps in this session, because your shell may not see the folder on `PATH` yet.
- `"onPath": false` means the folder isn't on the person's login `PATH`. See below.
- `"shadowedBy"` means another `iliad` comes first on `PATH`. Tell the person.
- `"ok": false` means it failed, and `code` is one of `usage`, `not-app-bundle`, `disk-image` (run it from `/Applications`, not the mounted disk image), `no-folder`, `folder-unusable`, `slot-taken`. Stop and tell the person.

Run this only when the installed version (from step 1) is 0.4.0 or later. Older versions don't know `install` and would open a folder named `install` instead. If the app is older, ask the person to update from inside Iliad (**Iliad MD → Check for Updates…**), then run this step.

If `onPath` is `false`, ask the person before you edit their shell profile. With their OK, run this.

```sh
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zprofile
```

Until they open a new terminal, use the full `linkPath`.

## 4. Install the skill

**Claude Code.** This copies the bundled skill to `~/.claude/skills/iliad/SKILL.md`, overwriting an older copy, so it is safe to rerun.

```sh
iliad skill install
```

Claude Code picks up new skills in new sessions. Tell the person to restart Claude Code if they want this session to use the skill.

**Codex and other agents that read `AGENTS.md`.** Ask the person where the skill should go.

- the global file (`~/.codex/AGENTS.md` for Codex), or
- the `AGENTS.md` in the folder they write in.

Then append the skill without its YAML front matter. Skip this if it is already there:

```sh
target="$HOME/.codex/AGENTS.md"               # or "/path/to/their/folder/AGENTS.md"
mkdir -p "$(dirname "$target")"
if grep -qs '^# Working with Iliad' "$target"; then
  echo "Iliad skill already in $target"
else
  { [ -s "$target" ] && printf '\n'; iliad skill print | awk 'NR==1 && /^---$/ {fm=1; next} fm && /^---$/ {fm=0; next} !fm'; } >> "$target"
  echo "Appended Iliad skill to $target"
fi
```

## 5. Verify

```sh
iliad --help                     # prints Usage:, exit 0
iliad status; echo "exit $?"     # "Iliad is not open." with exit 3 is fine
```

Then ask the person which folder they write in, and open it.

```sh
iliad ~/path/to/their/writing    # launches Iliad on that folder
iliad status                     # now lists the window and its folder
```

## 6. Tell the person

Keep it short and cover these points.

- **Iliad is installed** at `/Applications/Iliad MD.app` (give the version). The `iliad` command is at `<link path>`. The skill is installed for Claude Code (and/or added to `AGENTS.md`).
- **Open a folder.** Run `iliad <folder>`. In the app, use **Open Folder** on the start screen, or click the folder name at the top of the sidebar and choose **Open folder…**. Their files stay plain `.md` on disk.
- **Built-in AI works right away.** Inline completion (⌘, sentence, ⌘. paragraph, ⌘/ full idea) and the ✦ AI menu (select text, then ⌘↵) are included free, with a daily limit. No API key or account is needed, so do not ask the person for one. Text is sent only when they press one of those keys. In free mode it goes through Iliad's server to Groq, and neither keeps it (https://iliad.md/privacy/). For no daily limit and a direct connection, they can optionally paste their own Groq API key in **Writing assists → Use my key**. It is stored encrypted on the Mac, never in their files. Free AI needs Iliad 0.4.0 or later. Older versions asked for a Gemini key, so if an older version is installed, suggest updating.
- **How review works.** Keep Iliad open on the folder and ask an agent in a terminal on the same folder to edit a document. Each change appears in the document as a chunk with **Keep** or **Restore**, and **Keep all** and **Restore all** act on the whole document. Changed documents are marked in the file tree.
- **Comments.** Comments on a selection go to `name.comments.md`. Agents with the skill read them, so the person can say "address my comments in the open doc".

## Troubleshooting

| Symptom | Fix |
| --- | --- |
| `curl: (22) ... 404` on both URLs | The release is between uploads, or the asset name changed. Open https://github.com/brainforwarding/iliad/releases/latest, find the file ending in `-mac-arm64.dmg`, and use its URL. Check it against the `sha512` for that file in `latest-mac.yml`. |
| `SHA-512 mismatch` | A new release may have been published mid-download, so the stable file and `latest-mac.yml` disagree. Rerun step 2b once. If it still fails, stop and tell the person. |
| `hdiutil: attach failed` | Run `hdiutil info` to check whether an earlier mount is still there. Detach it with `hdiutil detach <mountpoint>` and retry. |
| `spctl` says `rejected` | Do not bypass it. Re-download. If it is still rejected, stop and report it to the person. |
| `iliad: command not found` | The link folder is not on `PATH`. See step 3, or call it by full path. |
| `iliad` runs another program | Another tool owns that name earlier on `PATH`. Run `which -a iliad` to see which one. Use the full path to Iliad's link, or ask the person which should win. |
| `Could not find the bundled Iliad skill` | The link points at a moved or deleted app. Rerun step 3. |
| `iliad open` says `Not a Markdown file` or `does not show hidden or ignored files` | Iliad opens only `.md`, `.markdown`, `.mdown` and `.mkd` files, and hides dotfiles, `node_modules`, `dist`, and `*.tmp` paths. |

## Reinstall (only if asked)

Use this only when the person explicitly asks to reinstall, for example because the in-app update did not work. It quits Iliad and replaces the app.

1. Warn the person that Iliad will quit. Autosave runs on quit, but they should make sure nothing is mid-edit.
2. Run `osascript -e 'quit app "Iliad MD"'`.
3. Wait until `pgrep -x "Iliad MD"` prints nothing.
4. Run `rm -rf "/Applications/Iliad MD.app"`.
5. Run step 2 (with Homebrew, run `brew reinstall --cask brainforwarding/tap/iliad-md`).

The command link and the skill don't need to change.

## Uninstall

If Iliad was installed with Homebrew, run `brew uninstall --cask iliad-md` and then remove the skill with `rm -rf "$HOME/.claude/skills/iliad"`. Otherwise, run this.

```sh
osascript -e 'quit app "Iliad MD"' 2>/dev/null
rm -rf "/Applications/Iliad MD.app"
for l in /opt/homebrew/bin/iliad /usr/local/bin/iliad "$HOME/.local/bin/iliad"; do
  [ -L "$l" ] && case "$(readlink "$l")" in *.app/Contents/Resources/bin/iliad) rm "$l";; esac
done
rm -rf "$HOME/.claude/skills/iliad"
```

This leaves the person's Markdown files and settings (`~/Library/Application Support/Iliad MD`) untouched.
