karajan-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- karajan_cli-0.1.0/PKG-INFO +229 -0
- karajan_cli-0.1.0/README.md +208 -0
- karajan_cli-0.1.0/karajan/__init__.py +4 -0
- karajan_cli-0.1.0/karajan/agents/architect.md +23 -0
- karajan_cli-0.1.0/karajan/agents/qa.md +13 -0
- karajan_cli-0.1.0/karajan/agents/researcher.md +13 -0
- karajan_cli-0.1.0/karajan/agents/reviewer.md +13 -0
- karajan_cli-0.1.0/karajan/cli.py +102 -0
- karajan_cli-0.1.0/karajan/commands/__init__.py +2 -0
- karajan_cli-0.1.0/karajan/commands/config.py +89 -0
- karajan_cli-0.1.0/karajan/commands/init.py +247 -0
- karajan_cli-0.1.0/karajan/commands/logs.py +30 -0
- karajan_cli-0.1.0/karajan/commands/models.py +49 -0
- karajan_cli-0.1.0/karajan/commands/profiles.py +23 -0
- karajan_cli-0.1.0/karajan/commands/status.py +50 -0
- karajan_cli-0.1.0/karajan/commands/task.py +57 -0
- karajan_cli-0.1.0/karajan/config.py +241 -0
- karajan_cli-0.1.0/karajan/graph.py +148 -0
- karajan_cli-0.1.0/karajan/nodes/__init__.py +2 -0
- karajan_cli-0.1.0/karajan/nodes/architect.py +25 -0
- karajan_cli-0.1.0/karajan/nodes/dev.py +66 -0
- karajan_cli-0.1.0/karajan/nodes/hitl.py +31 -0
- karajan_cli-0.1.0/karajan/nodes/prd.py +26 -0
- karajan_cli-0.1.0/karajan/nodes/qa.py +20 -0
- karajan_cli-0.1.0/karajan/nodes/research.py +26 -0
- karajan_cli-0.1.0/karajan/nodes/reviewer.py +20 -0
- karajan_cli-0.1.0/karajan/profiles/solo.toml +27 -0
- karajan_cli-0.1.0/karajan/profiles/team.toml +28 -0
- karajan_cli-0.1.0/karajan/scripts/__init__.py +2 -0
- karajan_cli-0.1.0/karajan/scripts/github.py +8 -0
- karajan_cli-0.1.0/karajan/scripts/logger.py +150 -0
- karajan_cli-0.1.0/karajan/scripts/tracker.py +145 -0
- karajan_cli-0.1.0/karajan_cli.egg-info/PKG-INFO +229 -0
- karajan_cli-0.1.0/karajan_cli.egg-info/SOURCES.txt +42 -0
- karajan_cli-0.1.0/karajan_cli.egg-info/dependency_links.txt +1 -0
- karajan_cli-0.1.0/karajan_cli.egg-info/entry_points.txt +2 -0
- karajan_cli-0.1.0/karajan_cli.egg-info/requires.txt +13 -0
- karajan_cli-0.1.0/karajan_cli.egg-info/top_level.txt +1 -0
- karajan_cli-0.1.0/pyproject.toml +46 -0
- karajan_cli-0.1.0/setup.cfg +4 -0
- karajan_cli-0.1.0/tests/test_config.py +54 -0
- karajan_cli-0.1.0/tests/test_init.py +76 -0
- karajan_cli-0.1.0/tests/test_integration.py +102 -0
- karajan_cli-0.1.0/tests/test_workflow_dry_run.py +64 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: karajan-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An AI agent harness for software engineers. Built on opencode + LangGraph.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: ai,agents,langgraph,opencode,workflow,engineering
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: langgraph>=0.2.0
|
|
10
|
+
Requires-Dist: litellm>=1.40.0
|
|
11
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
12
|
+
Requires-Dist: requests>=2.31.0
|
|
13
|
+
Requires-Dist: typer>=0.12.0
|
|
14
|
+
Requires-Dist: rich>=13.0.0
|
|
15
|
+
Requires-Dist: pydantic>=2.0.0
|
|
16
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
21
|
+
|
|
22
|
+
# Karajan
|
|
23
|
+
|
|
24
|
+
**An AI agent harness for software engineers.**
|
|
25
|
+
Built on [opencode](https://opencode.ai) + [LangGraph](https://langchain-ai.github.io/langgraph/).
|
|
26
|
+
|
|
27
|
+
> Named after Herbert von Karajan — the conductor who coordinates every musician
|
|
28
|
+
> without playing a single instrument himself.
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
Research → Architect → [YOU] → PRD → [YOU] → Dev → Reviewer → QA ⟲ → [YOU] → Done
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install karajan
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or from source (development):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git clone https://github.com/TU_USER/karajan
|
|
46
|
+
cd karajan
|
|
47
|
+
pip install -e .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# 1. Go to your project
|
|
54
|
+
cd ~/projects/my-app
|
|
55
|
+
|
|
56
|
+
# 2. Initialize karajan
|
|
57
|
+
karajan init --profile solo # or: --profile team
|
|
58
|
+
|
|
59
|
+
# 3. Fill in .agent/CONTEXT.md with your project details
|
|
60
|
+
# 4. Copy .env.karajan.example to .env and add your API keys
|
|
61
|
+
|
|
62
|
+
# 5. Run a workflow
|
|
63
|
+
karajan task QR-42
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Commands
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
karajan init [--profile solo|team] # Initialize in current project
|
|
72
|
+
karajan task <ticket> # Run full workflow
|
|
73
|
+
karajan status [ticket] # Show active workflows
|
|
74
|
+
karajan models [--provider X] # List available models
|
|
75
|
+
karajan profiles # List profiles and their defaults
|
|
76
|
+
karajan config --show # Show current project config
|
|
77
|
+
karajan version # Show version
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Model switching (per run)
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Use profile defaults
|
|
84
|
+
karajan task QR-42
|
|
85
|
+
|
|
86
|
+
# Override reasoning model (Research, Architect, PRD, Reviewer)
|
|
87
|
+
karajan task QR-42 --model anthropic/claude-sonnet-4-20250514
|
|
88
|
+
|
|
89
|
+
# Override dev model (what opencode uses internally)
|
|
90
|
+
karajan task QR-42 --dev-model ollama/qwen2.5-coder:14b
|
|
91
|
+
|
|
92
|
+
# Override all three independently
|
|
93
|
+
karajan task QR-42 \
|
|
94
|
+
--model google/gemini-2.0-flash \
|
|
95
|
+
--dev-model ollama/qwen2.5-coder:14b \
|
|
96
|
+
--qa-model ollama/qwen2.5:7b
|
|
97
|
+
|
|
98
|
+
# Resume interrupted workflow
|
|
99
|
+
karajan task QR-42 --from-stage dev
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Profiles
|
|
105
|
+
|
|
106
|
+
Profiles live in `karajan/profiles/` and ship with the package.
|
|
107
|
+
No separate repos needed — everything in one place.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
karajan profiles # see all profiles and their defaults
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| | `solo` | `team` |
|
|
114
|
+
|--|--|--|
|
|
115
|
+
| Use case | Personal side-projects | Company engineering team |
|
|
116
|
+
| Tracker | GitHub Issues + Projects | Jira |
|
|
117
|
+
| Dev CLI | opencode | Claude Code |
|
|
118
|
+
| Reasoning model | Gemini Flash | Gemini Flash |
|
|
119
|
+
| Dev model | Qwen2.5-Coder 14B (local) | Claude Sonnet |
|
|
120
|
+
| QA model | Qwen2.5 7B (local) | Claude Haiku |
|
|
121
|
+
| Observability | Local logs | Langfuse |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Workflow
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
karajan task QR-42
|
|
129
|
+
→ Fetches ticket (GitHub Issues or Jira)
|
|
130
|
+
→ Research agent — understands context and risks
|
|
131
|
+
→ Architect agent — designs technical plan
|
|
132
|
+
→ [YOU review plan] ← HITL #1
|
|
133
|
+
→ PRD agent — documents the feature
|
|
134
|
+
→ [YOU review PRD] ← HITL #2
|
|
135
|
+
→ Dev agent — opencode/Claude Code implements
|
|
136
|
+
→ Reviewer agent — code review
|
|
137
|
+
→ QA agent — validates, auto-retries Dev if fails (max 2x)
|
|
138
|
+
→ PR opened in GitHub
|
|
139
|
+
→ [YOU review PR] ← HITL #3
|
|
140
|
+
→ Done
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## What karajan init creates
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
your-project/
|
|
149
|
+
.agent/
|
|
150
|
+
CONTEXT.md ← what this project is
|
|
151
|
+
STACK.md ← technologies and versions
|
|
152
|
+
DECISIONS.md ← architecture decisions (ADRs)
|
|
153
|
+
CONSTRAINTS.md ← what agents can't touch
|
|
154
|
+
TASKS.md ← current work state
|
|
155
|
+
AGENTS.md ← agent instructions
|
|
156
|
+
.agents/
|
|
157
|
+
architect.md ← opencode architect agent definition
|
|
158
|
+
researcher.md ← opencode research agent definition
|
|
159
|
+
reviewer.md ← opencode reviewer agent definition
|
|
160
|
+
qa.md ← opencode QA agent definition
|
|
161
|
+
.karajan/
|
|
162
|
+
config.toml ← project-level config (profile, model overrides)
|
|
163
|
+
.env.karajan.example
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Structure
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
karajan/
|
|
172
|
+
karajan/
|
|
173
|
+
cli.py ← entry point (karajan command)
|
|
174
|
+
config.py ← config loader with full hierarchy
|
|
175
|
+
graph.py ← LangGraph orchestrator
|
|
176
|
+
profiles/
|
|
177
|
+
solo.toml ← solo profile defaults
|
|
178
|
+
team.toml ← team profile defaults
|
|
179
|
+
nodes/
|
|
180
|
+
research.py ← Research node
|
|
181
|
+
architect.py ← Architect node
|
|
182
|
+
prd.py ← PRD node
|
|
183
|
+
dev.py ← Dev node (opencode / Claude Code)
|
|
184
|
+
reviewer.py ← Reviewer node
|
|
185
|
+
qa.py ← QA node
|
|
186
|
+
hitl.py ← Human-in-the-loop node
|
|
187
|
+
agents/
|
|
188
|
+
architect.md ← opencode agent definition
|
|
189
|
+
researcher.md ← opencode agent definition
|
|
190
|
+
reviewer.md ← opencode agent definition
|
|
191
|
+
qa.md ← opencode agent definition
|
|
192
|
+
commands/
|
|
193
|
+
init.py ← karajan init
|
|
194
|
+
task.py ← karajan task
|
|
195
|
+
status.py ← karajan status
|
|
196
|
+
models.py ← karajan models
|
|
197
|
+
config.py ← karajan config
|
|
198
|
+
scripts/
|
|
199
|
+
tracker.py ← GitHub Issues + Jira unified
|
|
200
|
+
github.py ← PR creation
|
|
201
|
+
pyproject.toml ← pip install config
|
|
202
|
+
README.md
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Config hierarchy
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
CLI flags (--model, --dev-model, --profile)
|
|
211
|
+
> environment variables (KARAJAN_MODEL_*, GEMINI_API_KEY, etc.)
|
|
212
|
+
> .karajan/config.toml (per project)
|
|
213
|
+
> karajan/profiles/<profile>.toml (package defaults)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Requirements
|
|
219
|
+
|
|
220
|
+
- Python 3.11+
|
|
221
|
+
- [opencode](https://opencode.ai) (`npm install -g opencode`) — solo profile
|
|
222
|
+
- [Claude Code](https://claude.ai/code) — team profile
|
|
223
|
+
- Ollama (optional, for local models): https://ollama.com
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Karajan
|
|
2
|
+
|
|
3
|
+
**An AI agent harness for software engineers.**
|
|
4
|
+
Built on [opencode](https://opencode.ai) + [LangGraph](https://langchain-ai.github.io/langgraph/).
|
|
5
|
+
|
|
6
|
+
> Named after Herbert von Karajan — the conductor who coordinates every musician
|
|
7
|
+
> without playing a single instrument himself.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Research → Architect → [YOU] → PRD → [YOU] → Dev → Reviewer → QA ⟲ → [YOU] → Done
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install karajan
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or from source (development):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/TU_USER/karajan
|
|
25
|
+
cd karajan
|
|
26
|
+
pip install -e .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# 1. Go to your project
|
|
33
|
+
cd ~/projects/my-app
|
|
34
|
+
|
|
35
|
+
# 2. Initialize karajan
|
|
36
|
+
karajan init --profile solo # or: --profile team
|
|
37
|
+
|
|
38
|
+
# 3. Fill in .agent/CONTEXT.md with your project details
|
|
39
|
+
# 4. Copy .env.karajan.example to .env and add your API keys
|
|
40
|
+
|
|
41
|
+
# 5. Run a workflow
|
|
42
|
+
karajan task QR-42
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
karajan init [--profile solo|team] # Initialize in current project
|
|
51
|
+
karajan task <ticket> # Run full workflow
|
|
52
|
+
karajan status [ticket] # Show active workflows
|
|
53
|
+
karajan models [--provider X] # List available models
|
|
54
|
+
karajan profiles # List profiles and their defaults
|
|
55
|
+
karajan config --show # Show current project config
|
|
56
|
+
karajan version # Show version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Model switching (per run)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Use profile defaults
|
|
63
|
+
karajan task QR-42
|
|
64
|
+
|
|
65
|
+
# Override reasoning model (Research, Architect, PRD, Reviewer)
|
|
66
|
+
karajan task QR-42 --model anthropic/claude-sonnet-4-20250514
|
|
67
|
+
|
|
68
|
+
# Override dev model (what opencode uses internally)
|
|
69
|
+
karajan task QR-42 --dev-model ollama/qwen2.5-coder:14b
|
|
70
|
+
|
|
71
|
+
# Override all three independently
|
|
72
|
+
karajan task QR-42 \
|
|
73
|
+
--model google/gemini-2.0-flash \
|
|
74
|
+
--dev-model ollama/qwen2.5-coder:14b \
|
|
75
|
+
--qa-model ollama/qwen2.5:7b
|
|
76
|
+
|
|
77
|
+
# Resume interrupted workflow
|
|
78
|
+
karajan task QR-42 --from-stage dev
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Profiles
|
|
84
|
+
|
|
85
|
+
Profiles live in `karajan/profiles/` and ship with the package.
|
|
86
|
+
No separate repos needed — everything in one place.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
karajan profiles # see all profiles and their defaults
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
| | `solo` | `team` |
|
|
93
|
+
|--|--|--|
|
|
94
|
+
| Use case | Personal side-projects | Company engineering team |
|
|
95
|
+
| Tracker | GitHub Issues + Projects | Jira |
|
|
96
|
+
| Dev CLI | opencode | Claude Code |
|
|
97
|
+
| Reasoning model | Gemini Flash | Gemini Flash |
|
|
98
|
+
| Dev model | Qwen2.5-Coder 14B (local) | Claude Sonnet |
|
|
99
|
+
| QA model | Qwen2.5 7B (local) | Claude Haiku |
|
|
100
|
+
| Observability | Local logs | Langfuse |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Workflow
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
karajan task QR-42
|
|
108
|
+
→ Fetches ticket (GitHub Issues or Jira)
|
|
109
|
+
→ Research agent — understands context and risks
|
|
110
|
+
→ Architect agent — designs technical plan
|
|
111
|
+
→ [YOU review plan] ← HITL #1
|
|
112
|
+
→ PRD agent — documents the feature
|
|
113
|
+
→ [YOU review PRD] ← HITL #2
|
|
114
|
+
→ Dev agent — opencode/Claude Code implements
|
|
115
|
+
→ Reviewer agent — code review
|
|
116
|
+
→ QA agent — validates, auto-retries Dev if fails (max 2x)
|
|
117
|
+
→ PR opened in GitHub
|
|
118
|
+
→ [YOU review PR] ← HITL #3
|
|
119
|
+
→ Done
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## What karajan init creates
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
your-project/
|
|
128
|
+
.agent/
|
|
129
|
+
CONTEXT.md ← what this project is
|
|
130
|
+
STACK.md ← technologies and versions
|
|
131
|
+
DECISIONS.md ← architecture decisions (ADRs)
|
|
132
|
+
CONSTRAINTS.md ← what agents can't touch
|
|
133
|
+
TASKS.md ← current work state
|
|
134
|
+
AGENTS.md ← agent instructions
|
|
135
|
+
.agents/
|
|
136
|
+
architect.md ← opencode architect agent definition
|
|
137
|
+
researcher.md ← opencode research agent definition
|
|
138
|
+
reviewer.md ← opencode reviewer agent definition
|
|
139
|
+
qa.md ← opencode QA agent definition
|
|
140
|
+
.karajan/
|
|
141
|
+
config.toml ← project-level config (profile, model overrides)
|
|
142
|
+
.env.karajan.example
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Structure
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
karajan/
|
|
151
|
+
karajan/
|
|
152
|
+
cli.py ← entry point (karajan command)
|
|
153
|
+
config.py ← config loader with full hierarchy
|
|
154
|
+
graph.py ← LangGraph orchestrator
|
|
155
|
+
profiles/
|
|
156
|
+
solo.toml ← solo profile defaults
|
|
157
|
+
team.toml ← team profile defaults
|
|
158
|
+
nodes/
|
|
159
|
+
research.py ← Research node
|
|
160
|
+
architect.py ← Architect node
|
|
161
|
+
prd.py ← PRD node
|
|
162
|
+
dev.py ← Dev node (opencode / Claude Code)
|
|
163
|
+
reviewer.py ← Reviewer node
|
|
164
|
+
qa.py ← QA node
|
|
165
|
+
hitl.py ← Human-in-the-loop node
|
|
166
|
+
agents/
|
|
167
|
+
architect.md ← opencode agent definition
|
|
168
|
+
researcher.md ← opencode agent definition
|
|
169
|
+
reviewer.md ← opencode agent definition
|
|
170
|
+
qa.md ← opencode agent definition
|
|
171
|
+
commands/
|
|
172
|
+
init.py ← karajan init
|
|
173
|
+
task.py ← karajan task
|
|
174
|
+
status.py ← karajan status
|
|
175
|
+
models.py ← karajan models
|
|
176
|
+
config.py ← karajan config
|
|
177
|
+
scripts/
|
|
178
|
+
tracker.py ← GitHub Issues + Jira unified
|
|
179
|
+
github.py ← PR creation
|
|
180
|
+
pyproject.toml ← pip install config
|
|
181
|
+
README.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Config hierarchy
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
CLI flags (--model, --dev-model, --profile)
|
|
190
|
+
> environment variables (KARAJAN_MODEL_*, GEMINI_API_KEY, etc.)
|
|
191
|
+
> .karajan/config.toml (per project)
|
|
192
|
+
> karajan/profiles/<profile>.toml (package defaults)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Requirements
|
|
198
|
+
|
|
199
|
+
- Python 3.11+
|
|
200
|
+
- [opencode](https://opencode.ai) (`npm install -g opencode`) — solo profile
|
|
201
|
+
- [Claude Code](https://claude.ai/code) — team profile
|
|
202
|
+
- Ollama (optional, for local models): https://ollama.com
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: architect
|
|
3
|
+
description: Technical planning agent. Designs solutions, writes ADRs, and produces implementation specs. Use before any coding task.
|
|
4
|
+
model: google/gemini-2.0-flash
|
|
5
|
+
temperature: 0.3
|
|
6
|
+
mode: primary
|
|
7
|
+
tools:
|
|
8
|
+
- read
|
|
9
|
+
- write
|
|
10
|
+
permissions:
|
|
11
|
+
allow:
|
|
12
|
+
- read: "**"
|
|
13
|
+
- write: ".agent/DECISIONS.md"
|
|
14
|
+
- write: ".workflow-state/**"
|
|
15
|
+
deny:
|
|
16
|
+
- write: "src/**"
|
|
17
|
+
- write: "*.ts"
|
|
18
|
+
- write: "*.py"
|
|
19
|
+
- bash: "*"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
You are a Software Architect with deep experience in TypeScript, Node.js, event-driven systems, and complex integrations.
|
|
23
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: researcher
|
|
3
|
+
description: Technical research agent. Gathers context, finds patterns, identifies risks before design begins. Always runs before architect.
|
|
4
|
+
model: google/gemini-2.0-flash
|
|
5
|
+
temperature: 0.2
|
|
6
|
+
mode: primary
|
|
7
|
+
tools:
|
|
8
|
+
- read
|
|
9
|
+
- web_search
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
You are a Technical Research Specialist.
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: Code review agent. Reviews diffs for correctness, conventions, and quality.
|
|
4
|
+
model: google/gemini-2.0-flash
|
|
5
|
+
temperature: 0.1
|
|
6
|
+
mode: primary
|
|
7
|
+
tools:
|
|
8
|
+
- read
|
|
9
|
+
- bash
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
You are a Tech Lead doing code review.
|
|
13
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Karajan CLI entry point."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
from typing import Sequence
|
|
7
|
+
|
|
8
|
+
from . import __version__
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
12
|
+
parser = argparse.ArgumentParser(
|
|
13
|
+
prog="karajan",
|
|
14
|
+
description="An AI agent harness for software engineers. Built on opencode + LangGraph.",
|
|
15
|
+
)
|
|
16
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
17
|
+
|
|
18
|
+
init_parser = subparsers.add_parser("init", help="Initialize in current project")
|
|
19
|
+
init_parser.add_argument("--profile", "-p", choices=["solo", "team"], default=None)
|
|
20
|
+
init_parser.add_argument("--force", "-f", action="store_true")
|
|
21
|
+
|
|
22
|
+
task_parser = subparsers.add_parser("task", help="Run full workflow")
|
|
23
|
+
task_parser.add_argument("ticket")
|
|
24
|
+
task_parser.add_argument("--model", "-m", default=None)
|
|
25
|
+
task_parser.add_argument("--dev-model", default=None)
|
|
26
|
+
task_parser.add_argument("--qa-model", default=None)
|
|
27
|
+
task_parser.add_argument("--from-stage", default=None)
|
|
28
|
+
task_parser.add_argument("--dry-run", action="store_true")
|
|
29
|
+
|
|
30
|
+
status_parser = subparsers.add_parser("status", help="Show active workflows")
|
|
31
|
+
status_parser.add_argument("ticket", nargs="?", default=None)
|
|
32
|
+
|
|
33
|
+
models_parser = subparsers.add_parser("models", help="List available models")
|
|
34
|
+
models_parser.add_argument("--provider", default=None)
|
|
35
|
+
|
|
36
|
+
config_parser = subparsers.add_parser("config", help="Show current project config")
|
|
37
|
+
config_parser.add_argument("--show", action="store_true")
|
|
38
|
+
config_parser.add_argument("--set", dest="set_key", default=None)
|
|
39
|
+
|
|
40
|
+
subparsers.add_parser("version", help="Show version")
|
|
41
|
+
subparsers.add_parser("profiles", help="List profiles and defaults")
|
|
42
|
+
|
|
43
|
+
logs_parser = subparsers.add_parser("logs", help="Show run logs and cost summary")
|
|
44
|
+
logs_parser.add_argument("ticket", nargs="?", default=None)
|
|
45
|
+
logs_parser.add_argument("--tail", "-n", type=int, default=20)
|
|
46
|
+
logs_parser.add_argument("--summary", "-s", action="store_true")
|
|
47
|
+
|
|
48
|
+
return parser
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def app(argv: Sequence[str] | None = None) -> None:
|
|
52
|
+
parser = _build_parser()
|
|
53
|
+
args = parser.parse_args(argv)
|
|
54
|
+
|
|
55
|
+
if args.command is None:
|
|
56
|
+
parser.print_help()
|
|
57
|
+
raise SystemExit(0)
|
|
58
|
+
|
|
59
|
+
if args.command == "init":
|
|
60
|
+
from .commands.init import run_init
|
|
61
|
+
|
|
62
|
+
run_init(profile=args.profile, force=args.force)
|
|
63
|
+
elif args.command == "task":
|
|
64
|
+
from .commands.task import run_task
|
|
65
|
+
|
|
66
|
+
run_task(
|
|
67
|
+
ticket=args.ticket,
|
|
68
|
+
model=args.model,
|
|
69
|
+
dev_model=args.dev_model,
|
|
70
|
+
qa_model=args.qa_model,
|
|
71
|
+
from_stage=args.from_stage,
|
|
72
|
+
dry_run=args.dry_run,
|
|
73
|
+
)
|
|
74
|
+
elif args.command == "status":
|
|
75
|
+
from .commands.status import run_status
|
|
76
|
+
|
|
77
|
+
run_status(ticket=args.ticket)
|
|
78
|
+
elif args.command == "models":
|
|
79
|
+
from .commands.models import run_models
|
|
80
|
+
|
|
81
|
+
run_models(provider=args.provider)
|
|
82
|
+
elif args.command == "config":
|
|
83
|
+
from .commands.config import run_config
|
|
84
|
+
|
|
85
|
+
run_config(show=args.show, set_key=args.set_key)
|
|
86
|
+
elif args.command == "version":
|
|
87
|
+
print(f"karajan v{__version__}")
|
|
88
|
+
elif args.command == "profiles":
|
|
89
|
+
from .commands.profiles import run_profiles
|
|
90
|
+
|
|
91
|
+
run_profiles()
|
|
92
|
+
elif args.command == "logs":
|
|
93
|
+
from .commands.logs import run_logs
|
|
94
|
+
|
|
95
|
+
run_logs(ticket=args.ticket, tail=args.tail, summary=args.summary)
|
|
96
|
+
else:
|
|
97
|
+
parser.error(f"Unknown command: {args.command}")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
app()
|
|
102
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Show or update Karajan config."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import tomllib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from ..config import dump_config_toml, load_config
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def run_config(show: bool = False, set_key: str = None):
|
|
12
|
+
config_path = Path(".karajan/config.toml")
|
|
13
|
+
|
|
14
|
+
if set_key:
|
|
15
|
+
_set_config_value(config_path, set_key)
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
if show or not config_path.exists():
|
|
19
|
+
config = load_config()
|
|
20
|
+
print(dump_config_toml(config.model_dump()))
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
print(config_path.read_text(encoding="utf-8"))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _set_config_value(config_path: Path, assignment: str):
|
|
27
|
+
if not config_path.exists():
|
|
28
|
+
print("No .karajan/config.toml found. Run karajan init first.")
|
|
29
|
+
raise SystemExit(1)
|
|
30
|
+
if "=" not in assignment:
|
|
31
|
+
print(f"Invalid config assignment: {assignment}")
|
|
32
|
+
raise SystemExit(1)
|
|
33
|
+
key, raw_value = (part.strip() for part in assignment.split("=", 1))
|
|
34
|
+
parts = [part for part in key.split(".") if part]
|
|
35
|
+
if not key or len(parts) != len(key.split(".")) or len(parts) > 2:
|
|
36
|
+
print(f"Invalid config path: {key}")
|
|
37
|
+
raise SystemExit(1)
|
|
38
|
+
with config_path.open("rb") as handle:
|
|
39
|
+
config = tomllib.load(handle)
|
|
40
|
+
target = _coerce_config_value(raw_value)
|
|
41
|
+
if len(parts) == 1:
|
|
42
|
+
if isinstance(config.get(parts[0]), dict):
|
|
43
|
+
print(f"Invalid config path: {key}")
|
|
44
|
+
raise SystemExit(1)
|
|
45
|
+
config[parts[0]] = target
|
|
46
|
+
else:
|
|
47
|
+
section, field = parts
|
|
48
|
+
section_data = config.get(section)
|
|
49
|
+
if section_data is None:
|
|
50
|
+
config[section] = {field: target}
|
|
51
|
+
elif isinstance(section_data, dict):
|
|
52
|
+
section_data[field] = target
|
|
53
|
+
else:
|
|
54
|
+
print(f"Invalid config path: {key}")
|
|
55
|
+
raise SystemExit(1)
|
|
56
|
+
_write_config(config_path, config)
|
|
57
|
+
print(f"✅ Set {key} = {_format_config_value(target)}")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _coerce_config_value(raw_value: str):
|
|
61
|
+
value = raw_value.strip()
|
|
62
|
+
lowered = value.lower()
|
|
63
|
+
if lowered == "true":
|
|
64
|
+
return True
|
|
65
|
+
if lowered == "false":
|
|
66
|
+
return False
|
|
67
|
+
try:
|
|
68
|
+
return int(value)
|
|
69
|
+
except ValueError:
|
|
70
|
+
try:
|
|
71
|
+
return float(value)
|
|
72
|
+
except ValueError:
|
|
73
|
+
return value
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _format_config_value(value) -> str:
|
|
77
|
+
if isinstance(value, bool):
|
|
78
|
+
return "true" if value else "false"
|
|
79
|
+
return str(value)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _write_config(config_path: Path, config: dict):
|
|
83
|
+
try:
|
|
84
|
+
import tomli_w
|
|
85
|
+
except ModuleNotFoundError:
|
|
86
|
+
config_path.write_text(dump_config_toml(config), encoding="utf-8")
|
|
87
|
+
return
|
|
88
|
+
with config_path.open("wb") as handle:
|
|
89
|
+
tomli_w.dump(config, handle)
|