Skip to content

Keen CLI — Phase 1 Progress Evaluation

Build & Test Status

Check Status
go build ./... ✅ Passes
go test ./... ✅ Passes (config, filesystem)

Task-by-Task Assessment

Task 1: Project Structure & Go Module ✅ Complete

Planned Actual Status
cmd/agent/main.go ✅ Present Done
internal/config/ ✅ Present (config.go, loader.go) Done
internal/filesystem/ ✅ Present (guard.go, gitawareness.go) Done
internal/cli/ ✅ Present (root.go, repl.go, setup.go) Done
configs/system_prompts/ ⚠️ Directory exists, empty Minimal
go.mod with deps ✅ cobra, yaml.v3, go-git, huh Done

Actual structure matches the plan closely. The addition of configs/providers/ (registry) is a welcome bonus not in the original phase 1 plan but specified in the later CLI design doc.


Task 2: Config System ✅ Complete

Design doc: output-4_config-design.md

Requirement Status Notes
GlobalConfig struct (JSON) active_provider, active_model, providers map
ProviderConfig struct models []string, api_key string
SessionConfig struct In-memory only, no persistence
ResolvedConfig struct Final merged config
Resolve() function Session > Global > Default resolution
Loader (Load/Save/Exists) JSON persistence to ~/.keen/configs.json
GetProviderConfig()
SetProviderConfig()
AddModel() Dedup logic included
GetFirstModel()
ConfigPath() / ConfigDir()
0600 file permissions In loader.go Save()
Unit tests 13 tests across config_test.go and loader_test.go

[!TIP] The config system is one of the most complete parts of the codebase — fully matching the design doc with good test coverage.

Minor deviation: The design doc has SetProviderConfig returning an error, but the implementation is void (no error return). The current implementation silently initializes the map if nil, which is fine.


Task 3: FileGuard ✅ Complete

Requirement Status Notes
Permission type (Denied/Granted/Pending) Enum with iota
Guard struct workingDir, blockedPaths, gitignore
NewGuard() constructor Injects working dir + GitAwareness
CheckPath() permission matrix read+inDir=Granted, write=Pending, outside=Pending
IsBlocked() Checks gitignore + sensitive paths + dotfiles
ResolvePath() Handles relative and absolute paths
IsInWorkingDir()
Blocked paths list /etc, /usr, /bin, etc.
Dotfile protection Blocks ~/.<anything>
Unit tests 8 test functions

Deviation from plan: The plan specified blocking path traversal (../) as PermissionDenied, but the implementation treats it as PermissionPending (asks user). The test explicitly documents this choice. This is arguably more flexible — the user can approve access to sibling directories.

[!NOTE] The plan listed ~/.ssh, ~/.aws as explicitly blocked sensitive paths. The implementation takes a broader approach: any path starting with ~/.<something> is blocked. This is stricter than the plan and a reasonable security choice.


Task 4: GitAwareness ✅ Complete

Requirement Status Notes
GitAwareness struct Uses go-git gitignore package
LoadGitignore() Parses single .gitignore file
LoadGitignoreRecursive() Walks directories for nested .gitignore
IsIgnored() Checks all loaded patterns
FilterPaths() Batch filter operation
Comments & blank lines Handled in parser
Glob patterns Via go-git library
Unit tests 5 test functions including recursive loading

What's missing from the plan: - ❌ Global gitignore (~/.gitignore_global) — not implemented - ❌ Caching of IsIgnored results — no cache layer - ❌ Negation patterns (!important.log) — no test for this (the library may support it, but it's untested) - ❌ Interface extraction — the plan specifies GitAwareness as an interface, but the implementation is a concrete struct. Guard depends on *GitAwareness directly, not an interface.


Task 5: Basic CLI ✅ Complete

Design doc: output-5_basic-cli.md

Requirement Status Notes
keen starts REPL Root command runs REPL
keen --version Via cobra's built-in version
Interactive setup (first run) Provider → API Key → Model flow
Provider registry (embedded YAML) configs/providers/registry.yaml
huh for interactive prompts Select + password input
Config saved after setup To ~/.keen/configs.json
REPL with styled output lipgloss styling, welcome banner
Signal handling (Ctrl+C) Graceful shutdown
/exit command
No CLI flags (all via prompts)

The REPL stub: The REPL currently echoes input back — it has no command routing, no /help, /plan, /work, /model, /clear, or /add commands. This is expected for a phase 1 stub.

No tests for CLI/setup/providers:

? github.com/user/keen-cli/cmd/agent       [no test files]
? github.com/user/keen-cli/configs/providers [no test files]
? github.com/user/keen-cli/internal/cli      [no test files]


Task 6: Structured Logging ✅ Complete

Requirement Status Notes
log/slog usage Standard library structured logging
Log level config Via KEEN_LOG_LEVEL env var
Logging in components Used in config loader, guard, config resolution

Deviation: The plan mentioned a dedicated internal/logger/ package. Instead, logging is configured directly in main.go using slog.SetDefault(). This is simpler and perfectly fine for the current stage.


Overall Scorecard

Task Plan Status Quality Tests
1. Project Structure ✅ Complete Good N/A
2. Config System ✅ Complete Strong 13 tests ✅
3. FileGuard ✅ Complete Strong 8 tests ✅
4. GitAwareness ⚠️ Mostly Complete Good (missing interface, cache, global gitignore) 5 tests ✅
5. Basic CLI ✅ Complete Good ❌ No tests
6. Logging ✅ Complete Simple but effective N/A

Summary

Phase 1 is ~90% complete. All six tasks have working implementations. The project builds, tests pass, and the binary runs. The remaining gaps are:

  1. GitAwareness interface — not extracted (breaks RFC design)
  2. No caching in GitAwareness (plan specified it)
  3. No global gitignore support
  4. No tests for internal/cli/, configs/providers/, or cmd/agent/
  5. prompt.go deletion — mentioned in the basic CLI plan as something to remove, but it doesn't exist (already done or never created)
  6. REPL is a stub — only echoes input, no command routing (expected for phase 1)

The code quality is clean, idiomatic Go. No comments clutter the code. Dependencies are minimal and well-chosen. The security model (FileGuard + GitAwareness integration) is solid.