Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/actions/setup-deps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ runs:
- name: Create workspace
shell: bash
run: |
printf 'go 1.26.5\n\nuse .\n\nreplace (\n\tgithub.com/GrayCodeAI/hawk-core-contracts => ./external/hawk-core-contracts\n\tgithub.com/GrayCodeAI/eyrie => ./external/eyrie\n\tgithub.com/GrayCodeAI/inspect => ./external/inspect\n\tgithub.com/GrayCodeAI/sight => ./external/sight\n\tgithub.com/GrayCodeAI/tok => ./external/tok\n\tgithub.com/GrayCodeAI/trace => ./external/trace\n\tgithub.com/GrayCodeAI/yaad => ./external/yaad\n)\n' > go.work
printf 'go 1.26.5\n\nuse .\n\nreplace (\n\tgithub.com/GrayCodeAI/hawk-core-contracts => ./external/hawk-core-contracts\n\tgithub.com/GrayCodeAI/eyrie => ./external/eyrie\n\tgithub.com/GrayCodeAI/inspect => ./external/inspect\n\tgithub.com/GrayCodeAI/sight => ./external/sight\n\tgithub.com/GrayCodeAI/tok => ./external/tok\n\tgithub.com/GrayCodeAI/trace => ./external/trace\n\tgithub.com/GrayCodeAI/yaad => ./external/yaad\n\tgithub.com/GrayCodeAI/hawk-mcpkit => ./external/hawk-mcpkit\n)\n' > go.work
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,22 @@ jobs:
run: go mod verify
- name: workspace points at external checkouts
run: |
for module in hawk-core-contracts eyrie inspect sight tok trace yaad; do
for module in hawk-core-contracts eyrie inspect sight tok trace yaad hawk-mcpkit; do
if ! grep -q "./external/${module}" go.work; then
echo "::error::go.work must include ./external/${module}."
cat go.work
exit 1
fi
done
- name: Validate every Go module independently
run: |
while IFS= read -r modfile; do
dir=$(dirname "$modfile")
echo "==> validating $dir"
(cd "$dir" && GOWORK=off go mod tidy -diff)
(cd "$dir" && GOWORK=off go mod verify)
(cd "$dir" && GOWORK=off go test ./... -count=1 -timeout=300s)
done < <(find . -name go.mod -not -path './.git/*' -not -path './external/*' -print | sort)

public-modules:
name: public module graph
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,15 @@ clean: ## Remove build artefacts.
# Setup — bootstrap local development environment.
# ---------------------------------------------------------------------------
FOUNDATION_REPOS := hawk-core-contracts
ECO_REPOS := eyrie inspect sight tok trace yaad
ECO_REPOS := eyrie inspect sight tok trace yaad hawk-mcpkit
WORKSPACE_REPOS := $(FOUNDATION_REPOS) $(ECO_REPOS)

setup: ## Set up local development environment (go.work + external repos).
@echo "=== Setting up hawk development environment ==="
@mkdir -p external
@for repo in $(WORKSPACE_REPOS); do \
dest="external/$$repo"; \
if [ -d "$$dest/.git" ]; then \
if git -C "$$dest" rev-parse --git-dir >/dev/null 2>&1; then \
echo "✓ $$dest already exists"; \
else \
commit=$$(git ls-tree HEAD "$$dest" 2>/dev/null | awk '{print $$3}' || true); \
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ hawk is an AI-powered coding agent that lives in your terminal. It reads your co

**Developer path:** one machine, keychain credentials, local memory. Run `hawk path` to check readiness.

- **Model-agnostic** — supports 23 first-class providers through [eyrie](https://github.com/GrayCodeAI/eyrie), including Anthropic, OpenAI, Gemini, Concentrate AI (pay-as-you-go), DeepSeek, and Ollama
- **Model-agnostic** — supports 28 first-class providers through [eyrie](https://github.com/GrayCodeAI/eyrie), including Anthropic, OpenAI, Gemini, Fireworks AI, Concentrate AI (pay-as-you-go), DeepSeek, and Ollama
- **Zero CGO** — single static binary, cross-compiled for linux/darwin/windows on amd64/arm64
- **Privacy-first** — your code never leaves your machine except to the LLM API you choose
- **Docker-only execution** — agent commands run in an isolated container and
Expand Down Expand Up @@ -345,6 +345,7 @@ hawk works with any LLM provider. **Developer path:** paste keys in `/config` (s
| OpenAI | `openai` | `OPENAI_API_KEY` |
| Google Gemini | `gemini` | `GEMINI_API_KEY` |
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
| Fireworks AI | `fireworks` | `FIREWORKS_API_KEY` |
| xAI (Grok) | `grok` | `XAI_API_KEY` |
| Z.AI | `z-ai` | `ZAI_API_KEY` |
| CanopyWave | `canopywave` | `CANOPYWAVE_API_KEY` |
Expand Down
4 changes: 2 additions & 2 deletions docs/ECOSYSTEM-CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ setting; the unified key is rendered down to it.
|---------------------------------|-------------|--------------------------------------------------|
| `model.default` | hawk | `HAWK_MODEL` env / `config.json` |
| `model.small_fast` | hawk | `GRAYCODE_SMALL_FAST_MODEL` env |
| `providers[].api_key_env` | eyrie/hawk | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `XAI_API_KEY`, `ZAI_API_KEY`, `CANOPYWAVE_API_KEY` |
| `providers[].base_url_env` | eyrie | `ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL` / `OPENAI_API_BASE`, `OLLAMA_BASE_URL` |
| `providers[].api_key_env` | eyrie/hawk | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, `XAI_API_KEY`, `ZAI_API_KEY`, `CANOPYWAVE_API_KEY`, `FIREWORKS_API_KEY` |
| `providers[].base_url_env` | eyrie | `ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL` / `OPENAI_API_BASE`, `OLLAMA_BASE_URL`, `FIREWORKS_BASE_URL` |
| `providers[].model` (openai) | eyrie | `OPENAI_MODEL` env |
| `providers[].model` (gemini) | eyrie | `GEMINI_MODEL` env |
| `providers[].model` (anthropic) | eyrie | `ANTHROPIC_MODEL` env |
Expand Down
9 changes: 8 additions & 1 deletion docs/user-guide/02-authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Hawk supports multiple providers:
| OpenAI | `openai` | `OPENAI_API_KEY` |
| Google Gemini | `gemini` | `GEMINI_API_KEY` |
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
| Fireworks AI | `fireworks` | `FIREWORKS_API_KEY` |
| Ollama (local) | `ollama` | `OLLAMA_BASE_URL` (no API key) |

### Setting Up Credentials
Expand All @@ -38,6 +39,12 @@ export XAI_API_KEY="xai-..."
hawk
```

Fireworks uses its OpenAI-compatible API. Set `FIREWORKS_API_KEY`; the default
base URL is `https://api.fireworks.ai/inference/v1`. See the official
[quickstart](https://docs.fireworks.ai/getting-started/quickstart),
[API reference](https://docs.fireworks.ai/api-reference/introduction), and
[models overview](https://docs.fireworks.ai/models/overview).

---

## Provider Configuration
Expand Down Expand Up @@ -228,4 +235,4 @@ Any provider can be set as default in your settings:

---

© 2026 GrayCode AI. All rights reserved.
© 2026 GrayCode AI. All rights reserved.
2 changes: 1 addition & 1 deletion go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 10 additions & 6 deletions internal/multiagent/watchdog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import (
)

func TestWatchdog_NoStall(t *testing.T) {
stallCalled := false
stallCalled := make(chan struct{}, 1)
w := NewWatchdog(WatchdogConfig{
StallTimeout: 100 * time.Millisecond,
CheckInterval: 20 * time.Millisecond,
}, func(featureID string) {
stallCalled = true
stallCalled <- struct{}{}
})

w.Register("feat-1")
Expand All @@ -25,8 +25,10 @@ func TestWatchdog_NoStall(t *testing.T) {
w.Touch("feat-1")
<-ctx.Done()

if stallCalled {
select {
case <-stallCalled:
t.Fatal("expected no stall callback when feature is touched within timeout")
default:
}
}

Expand Down Expand Up @@ -62,12 +64,12 @@ func TestWatchdog_StallDetected(t *testing.T) {
}

func TestWatchdog_Unregister_StopsMonitoring(t *testing.T) {
stallCalled := false
stallCalled := make(chan struct{}, 1)
w := NewWatchdog(WatchdogConfig{
StallTimeout: 50 * time.Millisecond,
CheckInterval: 20 * time.Millisecond,
}, func(featureID string) {
stallCalled = true
stallCalled <- struct{}{}
})

w.Register("feat-unreg")
Expand All @@ -79,8 +81,10 @@ func TestWatchdog_Unregister_StopsMonitoring(t *testing.T) {
go w.Run(ctx)
<-ctx.Done()

if stallCalled {
select {
case <-stallCalled:
t.Fatal("expected no stall callback after Unregister")
default:
}
}

Expand Down
2 changes: 1 addition & 1 deletion testdata/golden/help_root.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
hawk is an AI coding agent that reads, writes, and runs code in your terminal.

It connects to 27 first-class LLM providers through eyrie, executes tools (file I/O, shell,
It connects to 28 first-class LLM providers through eyrie, executes tools (file I/O, shell,
git, web search), and manages sessions — all from a keyboard-driven TUI or
headless mode for scripts and CI.

Expand Down
Loading