Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a0e8a82
Use Eyrie deployment catalog for model routing
Patel230 May 18, 2026
ee812b6
chore: drop eyrie submodule; use sibling replace
Patel230 May 19, 2026
973671c
Integrate eyrie credentials, catalog discovery, and first-run setup.
Patel230 May 19, 2026
add0561
docs: update milestone plan with branch commits and phase status.
Patel230 May 19, 2026
a573b54
test: add milestone verification and clarify sandbox vs Docker help.
Patel230 May 19, 2026
ad316cc
Use keychain-only credentials with /config key remove and preflight.
Patel230 May 20, 2026
44d9d96
Fix CI: gofumpt and checkout matching eyrie branch in workflows.
Patel230 May 20, 2026
aa8572e
Fix golangci-lint issues for credential and catalog startup code.
Patel230 May 20, 2026
dba13a3
Do not fail CI when dependency graph is unavailable.
Patel230 May 20, 2026
fca2191
Polish Connect Center UX, TUI performance, and credential resilience.
Patel230 May 20, 2026
2a9d3be
Fix CI formatting and nil-safe gateway row rendering.
Patel230 May 20, 2026
da9d747
Fix golangci-lint failures for unused code and welcome cache.
Patel230 May 20, 2026
c53bd08
Remove dependency-review job when Dependency graph is disabled.
Patel230 May 20, 2026
ae0a0e9
Isolate provider.json in setup cache tests for CI shuffle.
Patel230 May 20, 2026
60e5fe4
Fix 7 security and correctness issues from code audit
Patel230 May 21, 2026
35236ce
Fix OpenRouter model resolution and context size display
Patel230 May 21, 2026
742c3a1
Polish hawk TUI spinner, welcome banner, and status bar UX.
Patel230 May 21, 2026
e2e1d8e
Fix gofumpt formatting in chat model status helper.
Patel230 May 21, 2026
1e53b96
Remove unused TUI color styles flagged by golangci-lint.
Patel230 May 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/actions/checkout-eyrie/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Checkout eyrie
description: Clone eyrie as a sibling repo for hawk go.work (../eyrie)

inputs:
ref:
description: Git ref to checkout (branch or tag)
required: false
default: main

runs:
using: composite
steps:
- name: Clone eyrie
shell: bash
run: |
set -euo pipefail
dest="${GITHUB_WORKSPACE}/../eyrie"
if [ -d "$dest/.git" ]; then
echo "eyrie already present at $dest"
exit 0
fi
git clone --depth=1 --branch "${{ inputs.ref }}" \
"https://github.com/GrayCodeAI/eyrie.git" "$dest"
2 changes: 1 addition & 1 deletion .github/actions/setup-deps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ runs:
- name: Create workspace
shell: bash
run: |
printf 'go 1.26.1\n\nuse .\n\nreplace (\n\tgithub.com/GrayCodeAI/eyrie => ../eyrie\n\tgithub.com/GrayCodeAI/tok => ../tok\n\tgithub.com/GrayCodeAI/yaad => ../yaad\n\tgithub.com/GrayCodeAI/inspect => ../inspect\n\tgithub.com/GrayCodeAI/sight => ../sight\n)\n' > go.work
printf 'go 1.26.3\n\nuse (\n\t.\n\t../eyrie\n\t../tok\n\t../yaad\n\t../inspect\n\t../sight\n)\n' > go.work
53 changes: 20 additions & 33 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -56,22 +54,23 @@ jobs:
fi

# -------------------------------------------------------------------------
# 2. Module hygiene — tidy, verify (Herm-style: submodule + go.work, no go.mod replace).
# 2. Module hygiene — tidy, verify (hawk + sibling eyrie via go.work + go.mod replace).
# -------------------------------------------------------------------------
module:
name: module hygiene
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/checkout-eyrie
with:
submodules: recursive
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: go work sync + module consistency
run: |
# Herm uses submodule + go.work only (no go.mod replace). go mod tidy can mis-resolve
# Eyrie is a sibling checkout (go.work + replace ../eyrie). go mod tidy can mis-resolve
# workspace modules here; go work sync is the supported workspace hygiene step.
go work sync
go build -mod=readonly -o /dev/null .
Expand All @@ -82,10 +81,10 @@ jobs:
fi
- name: go mod verify
run: go mod verify
- name: no replace directives in go.mod
- name: eyrie replace points at sibling
run: |
if grep -qE '^\s*replace\s' go.mod; then
echo "::error::go.mod must not use replace (Eyrie comes from submodule + go.work; see Herm / LangDAG)."
if ! grep -qE 'replace github\.com/GrayCodeAI/eyrie => \.\./eyrie' go.mod; then
echo "::error::go.mod must replace eyrie with ../eyrie (sibling checkout)."
grep -nE '^\s*replace\s' go.mod || true
exit 1
fi
Expand All @@ -98,8 +97,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/checkout-eyrie
with:
submodules: recursive
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -116,8 +116,9 @@ jobs:
needs: [format, vet]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/checkout-eyrie
with:
submodules: recursive
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -136,8 +137,9 @@ jobs:
needs: [format, vet]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/checkout-eyrie
with:
submodules: recursive
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down Expand Up @@ -171,8 +173,9 @@ jobs:
needs: [format, vet]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/checkout-eyrie
with:
submodules: recursive
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand All @@ -194,43 +197,26 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
- uses: trufflesecurity/trufflehog@0fa069c12f0c7baf431041cd1e564a9c5058846c # main 2026-05-18
with:
extra_args: --only-verified

# -------------------------------------------------------------------------
# 8. Dependency review — only on pull requests.
# -------------------------------------------------------------------------
dependency-review:
name: dependency review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0

# -------------------------------------------------------------------------
# 9. Markdown lint — validate documentation quality.
# 8. Markdown lint — validate documentation quality.
# -------------------------------------------------------------------------
markdown:
name: markdown
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
- name: Run markdownlint-cli2
run: |
npm install -g markdownlint-cli2
printf '%s\n' '{"ignores":["external/**"],"config":{"default":true,"line-length":false,"no-inline-html":false,"first-line-h1":false,"no-duplicate-heading":false,"no-emphasis-as-heading":false,"blanks-around-headings":false,"blanks-around-lists":false,"blanks-around-fences":false,"fenced-code-language":false,"table-column-style":false,"no-space-in-emphasis":false,"ol-prefix":false,"link-fragments":false,"blanks-around-tables":false,"table-column-count":false,"single-trailing-newline":false}}' > .markdownlint-cli2.jsonc
printf '%s\n' '{"config":{"default":true,"line-length":false,"no-inline-html":false,"first-line-h1":false,"no-duplicate-heading":false,"no-emphasis-as-heading":false,"blanks-around-headings":false,"blanks-around-lists":false,"blanks-around-fences":false,"fenced-code-language":false,"table-column-style":false,"no-space-in-emphasis":false,"ol-prefix":false,"link-fragments":false,"blanks-around-tables":false,"table-column-count":false,"single-trailing-newline":false}}' > .markdownlint-cli2.jsonc
markdownlint-cli2 '**/*.md'

# -------------------------------------------------------------------------
# 10. Cross-platform build matrix — zero CGO, all targets.
# 9. Cross-platform build matrix — zero CGO, all targets.
# -------------------------------------------------------------------------
build:
name: build (${{ matrix.goos }}/${{ matrix.goarch }})
Expand All @@ -246,8 +232,9 @@ jobs:
goarch: arm64
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/checkout-eyrie
with:
submodules: recursive
ref: ${{ github.head_ref || github.ref_name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ env.GO_VERSION }}
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # goreleaser needs full history for changelog
submodules: recursive

- uses: ./.github/actions/checkout-eyrie

- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
Expand Down
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

31 changes: 26 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,28 +70,29 @@ go test -race ./... # Run all tests

| Module | In `go.mod` | In-repo checkout | Used from |
|--------|-------------|------------------|-----------|
| eyrie | ✓ | **`external/eyrie`** submodule + **`go.work`** | Provider client, setup, streaming |
| eyrie | ✓ | sibling **`../eyrie`** + **`go.work`** + **`replace` in `go.mod`** | Provider client, setup, streaming |
| sight | ✓ | proxy (optional local `replace`) | `hawk sight`, `internal/bridge/sight` |
| inspect | ✓ | proxy | Inspect bridges |
| tok | ✓ | proxy | Tokenizer pipeline |
| yaad | ✓ | proxy | Memory bridge |
| trace | — | separate **`trace` CLI** | Session capture only; not a Go import |

**Eyrie submodule** (Herm / LangDAG-style):
**Eyrie sibling checkout** (hawk + eyrie):

```bash
git submodule update --init --recursive
# hawk-eco layout: clone eyrie next to hawk, then:
cd hawk && go work sync
```

Committed **`go.work`** lists `.` and **`./external/eyrie`** only. **`go.mod` must not contain `replace` directives** for Eyrie (CI enforces this).
Committed **`go.work`** lists `.` and **`../eyrie`**. **`go.mod`** includes **`replace github.com/GrayCodeAI/eyrie => ../eyrie`** (CI enforces this path).

**`shared/types`** forwards **`internal/types`** for **sight**, **inspect**, **tok**, and friends so they never import hawk `internal/` directly.

For sibling clones on one machine, use a **personal** parent **`go.work`** or temporary **`replace`** — do not commit those **`replace`** lines into **`go.mod`**.

### CI

- Checkout uses **`submodules: recursive`** so `external/eyrie` is populated
- CI clones **eyrie** to **`../eyrie`** via **`.github/actions/checkout-eyrie`**
- Module hygiene: **`go work sync`** and **`go build -mod=readonly`** (not `go mod tidy`, which mis-resolves workspace Eyrie)
- golangci-lint with errcheck, staticcheck, gosec, unused, misspell
- Multi-platform builds (linux/darwin/windows × amd64/arm64)
Expand All @@ -105,3 +106,23 @@ For sibling clones on one machine, use a **personal** parent **`go.work`** or te
- Landlock: filesystem access restrictions
- seccomp-bpf: blocks 21 dangerous syscalls
- Fallback: no-op on non-Linux (`internal/sandbox/landlock_other.go`)

## Milestone: API key → model → sandbox

Active branch: **`feature/secure-credentials-sandbox`** (hawk + eyrie sibling).

| Concern | Where |
|---------|--------|
| First-run `/config`, setup guards | `internal/config/setup_status.go`, `cmd/chat.go` |
| Keychain + `PersistAPIKey` / `RemoveStoredCredential` | `internal/config/credentials_store.go`, eyrie `credentials/` |
| Remove stored key (TUI) | `/config key remove` → `cmd/chat_config_remove.go` |
| Remove stored key (CLI) | `hawk credentials remove` → `cmd/credentials.go` |
| Catalog discover + routing only on disk | `internal/config/eyrie_apply.go`, eyrie `setup/apply_credentials.go` |
| Catalog empty / refresh hints | `internal/config/catalog_health.go`, `catalog_startup.go` |
| No API keys in `provider.json` | eyrie `SanitizeDeploymentConfigForDisk`, hawk `MigrateProviderSecrets` |
| Verification tests | `internal/config/milestone_verify_test.go`, `./scripts/verify-milestone.sh` |
| Plan + phase status | `plans/MILESTONE-api-key-model-sandbox.md` |

**Not in this milestone:** conversation DAG as source of truth, langdag Go import.

**`/sandbox` vs Docker:** `/sandbox` toggles **approval mode** in the TUI. **Docker container mode** is the default for bash (`shouldUseContainer`); use `--no-container` for host execution.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ hawk works with any LLM provider. Set your API key via environment variable or `
| Ollama | `OLLAMA_BASE_URL` (no key) |

Provider routing, model resolution, and retries are handled by [eyrie](https://github.com/GrayCodeAI/eyrie).
For deployment-aware routing, set `"deployment_routing": true` in `.hawk/settings.json`
or export `HAWK_DEPLOYMENT_ROUTING=true`. Hawk will route canonical model IDs through
Eyrie's deployment catalog, so new models can be exposed by refreshing the catalog
instead of changing Hawk. In chat, run `/refresh-model-catalog` to fetch the latest
deployment-aware catalog into `~/.eyrie/model_catalog.json`.

## Architecture

Expand Down Expand Up @@ -201,12 +206,12 @@ hawk/
hawk integrates these GrayCodeAI repos in three ways:

- **`go.mod` modules:** **eyrie**, **sight**, **inspect**, **tok**, **yaad** — pinned versions from the module proxy (same semver story across CI).
- **Submodule + `go.work`:** **eyrie** only — checked out under **`external/eyrie`** (`git submodule update --init --recursive`) so CI/builds always see the same Eyrie source layout as Herm-style repos.
- **Sibling + `go.work` + `replace`:** **eyrie** — clone [eyrie](https://github.com/GrayCodeAI/eyrie) next to hawk (`../eyrie`). `go.mod` uses `replace github.com/GrayCodeAI/eyrie => ../eyrie`. CI clones the same layout via **`.github/actions/checkout-eyrie`**.
- **Optional CLI (no Go import):** **trace** — installed separately; `hawk` shells into `trace` for session capture when present.

Cross-repo types (severity, etc.) are exported from **`github.com/GrayCodeAI/hawk/shared/types`** so **sight** / **inspect** / **tok** do not import **`internal/`**.

You may keep a **personal** parent **`go.work`** that lists sibling clones on disk (`../sight`, …); nothing besides **`external/eyrie`** is committed as a submodule in hawk.
You may keep a **personal** parent **`go.work`** that lists sibling clones on disk (`../sight`, …) for multi-repo development.

| Component | Repository | Purpose |
|---|---|---|
Expand Down
Loading