Skip to content

Commit fd5823e

Browse files
committed
Expose repo workflow contract
1 parent ac46ce4 commit fd5823e

14 files changed

Lines changed: 481 additions & 15 deletions

File tree

.rabbit/context.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ generator:
66
tool: dev.kit
77
repo: https://github.com/udx/dev.kit
88
version: 0.10.0
9-
generated_at: 2026-05-13T00:55:54Z
9+
generated_at: 2026-05-19T17:49:21Z
1010

1111
repo:
1212
name: dev.kit
@@ -70,14 +70,16 @@ gaps:
7070
dependencies:
7171
- repo: udx/reusable-workflows
7272
kind: reusable workflow
73-
resolved: false
73+
resolved: true
74+
archetype: workflow-repo
7475
used_by:
7576
- .github/workflows/context7-ops.yml
7677
- .github/workflows/npm-release-ops.yml
7778
- repo: udx/worker
7879
kind: manifest contract (deploy)
79-
resolved: false
80+
resolved: true
8081
declared_as: udx.io/worker-v1/deploy
82+
archetype: manifest-repo
8183
used_by:
8284
- deploy.yml
8385

@@ -163,4 +165,3 @@ manifests:
163165
- path reference: src/configs/context-config.yaml
164166
- path reference: src/configs/detection-signals.yaml
165167
- path reference: tests/suite.sh
166-

bin/dev-kit

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,94 @@ dev_kit_home_context_reason() {
309309
fi
310310
}
311311

312+
dev_kit_home_repo_workflow_status() {
313+
local repo_root="$1"
314+
local context_status="$2"
315+
local context_yaml_path="$3"
316+
local gap_count=0
317+
318+
[ -n "$repo_root" ] || {
319+
printf '%s' "unavailable"
320+
return 0
321+
}
322+
323+
case "$context_status" in
324+
missing)
325+
printf '%s' "needs_repo_context"
326+
return 0
327+
;;
328+
stale)
329+
printf '%s' "stale_context"
330+
return 0
331+
;;
332+
esac
333+
334+
if [ -n "$context_yaml_path" ] && [ -f "$context_yaml_path" ]; then
335+
gap_count="$(dev_kit_context_section_item_count "$context_yaml_path" "gaps" '^ - factor:')"
336+
else
337+
gap_count="$(dev_kit_repo_gap_count "$repo_root")"
338+
fi
339+
340+
if [ "${gap_count:-0}" -gt 0 ]; then
341+
printf '%s' "needs_repair"
342+
return 0
343+
fi
344+
345+
printf '%s' "ready"
346+
}
347+
348+
dev_kit_home_workflow_status() {
349+
local repo_detected="$1"
350+
local env_status="$2"
351+
local repo_status="$3"
352+
353+
if [ "$env_status" = "blocked" ]; then
354+
printf '%s' "blocked"
355+
return 0
356+
fi
357+
358+
if [ "$repo_detected" != "true" ]; then
359+
printf '%s' "workspace_only"
360+
return 0
361+
fi
362+
363+
case "$repo_status" in
364+
needs_repo_context|stale_context)
365+
printf '%s' "needs_repo_context"
366+
;;
367+
needs_repair)
368+
printf '%s' "needs_repair"
369+
;;
370+
*)
371+
printf '%s' "ready"
372+
;;
373+
esac
374+
}
375+
376+
dev_kit_home_workflow_json() {
377+
local repo_detected="$1"
378+
local repo_root="$2"
379+
local context_status="$3"
380+
local context_yaml_path="$4"
381+
local env_status=""
382+
local repo_status=""
383+
local workflow_status=""
384+
local jobs_json=""
385+
386+
env_status="$(dev_kit_env_workflow_status)"
387+
repo_status="$(dev_kit_home_repo_workflow_status "$repo_root" "$context_status" "$context_yaml_path")"
388+
workflow_status="$(dev_kit_home_workflow_status "$repo_detected" "$env_status" "$repo_status")"
389+
jobs_json="$(dev_kit_env_workflow_job_json)"
390+
391+
if [ "$repo_detected" = "true" ]; then
392+
jobs_json="${jobs_json}, $(dev_kit_repo_workflow_job_json "$repo_root" "$repo_status" "write" "$context_status")"
393+
fi
394+
395+
printf '{ "id": "dev-kit", "label": "Normalize repo and environment", "status": "%s", "jobs": [%s] }' \
396+
"$(dev_kit_json_escape "$workflow_status")" \
397+
"$jobs_json"
398+
}
399+
312400
dev_kit_run_home() {
313401
local format="${1:-text}"
314402
local state="installed"
@@ -319,6 +407,9 @@ dev_kit_run_home() {
319407
local context_yaml_path=""
320408
local context_status="none"
321409
local context_reason=""
410+
local env_workflow_status=""
411+
local repo_workflow_status=""
412+
local workflow_status=""
322413

323414
repo_root="$(dev_kit_repo_root "$repo_dir")"
324415
if [ -n "$repo_root" ]; then
@@ -344,11 +435,16 @@ dev_kit_run_home() {
344435
fi
345436
fi
346437

438+
env_workflow_status="$(dev_kit_env_workflow_status)"
439+
repo_workflow_status="$(dev_kit_home_repo_workflow_status "$repo_root" "$context_status" "$context_yaml_path")"
440+
workflow_status="$(dev_kit_home_workflow_status "$repo_detected" "$env_workflow_status" "$repo_workflow_status")"
441+
347442
if [ "$format" = "json" ]; then
348443
printf '{\n'
349444
printf ' "name": "dev.kit",\n'
350445
printf ' "home": "%s",\n' "$(dev_kit_json_escape "$DEV_KIT_HOME")"
351446
printf ' "state": "%s",\n' "$(dev_kit_json_escape "$state")"
447+
printf ' "workflow": %s,\n' "$(dev_kit_home_workflow_json "$repo_detected" "$repo_root" "$context_status" "$context_yaml_path")"
352448
printf ' "workspace": {\n'
353449
printf ' "path": "%s",\n' "$(dev_kit_json_escape "$repo_dir")"
354450
printf ' "repo_detected": %s,\n' "$repo_detected"
@@ -392,6 +488,13 @@ dev_kit_run_home() {
392488
# Text mode: print title immediately, then compute and print progressively
393489
dev_kit_output_title "dev.kit"
394490

491+
dev_kit_output_section "workflow"
492+
dev_kit_output_row "status" "$workflow_status"
493+
dev_kit_output_row "env" "$env_workflow_status"
494+
if [ "$repo_detected" = "true" ]; then
495+
dev_kit_output_row "repo" "$repo_workflow_status"
496+
fi
497+
395498
# ── Environment: list tools by category with what they enable ───────────────
396499
local _env_line _env_cat _env_val _prev_cat=""
397500
while IFS= read -r _env_line; do
@@ -422,7 +525,6 @@ EOF
422525
context_yaml_path="$(dev_kit_context_yaml_path "$repo_root")"
423526

424527
dev_kit_output_summary "${summary_name}${summary_archetype}"
425-
426528
dev_kit_output_section "context"
427529
dev_kit_output_row "path" "$context_yaml_path"
428530
dev_kit_output_row "status" "$context_status"

bin/scripts/install.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ main() {
173173

174174
find "$DEV_KIT_HOME/bin" -type f -exec chmod +x {} \;
175175
ln -sfn "$DEV_KIT_HOME/bin/dev-kit" "$target"
176+
ln -sfn "$DEV_KIT_HOME/bin/dev-kit" "${DEV_KIT_BIN_DIR}/dev-kit"
176177

177178
if command -v dev_kit_output_title >/dev/null 2>&1; then
178179
dev_kit_output_title "Installed dev.kit"

changes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
### unreleased
44

5+
- Expose repo-centric workflow status in `dev.kit`, `dev.kit env`, and `dev.kit repo` output so environment checks, context refresh, and gap repair appear as one repo-owned loop
6+
- Clarify the repo contract boundary between deterministic structured parsing and interpreted prose/session intent
7+
58
### 0.10.0
69

710
- Remove `dev.kit agent` so `.rabbit/context.yaml` is the single generated repo contract

docs/context-coverage.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ It should answer three questions:
1414

1515
For the boundary between generated contract data and durable repo docs, see [Repo Contract Boundary](repo-contract-boundary.md).
1616

17+
Structured sources such as YAML, JSON, workflow refs, and manifest metadata should be parsed programmatically where possible. Prose sources such as Markdown docs, prompts, reviews, and session notes should be treated as interpreted intent unless they point to a concrete script, manifest, or command.
18+
1719
Typical sections include:
1820

1921
- generator metadata

docs/repo-contract-boundary.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@ Use **scripts and manifests** for programmatic execution:
2020
- deploy manifests such as `deploy.yml`
2121
- checked-in config examples when they are part of the runnable contract
2222

23+
Use **structured refs** for deterministic parsing:
24+
25+
- YAML and JSON manifests
26+
- package and tool config files
27+
- workflow references
28+
- version, kind, and description metadata
29+
- explicit command definitions
30+
31+
Use **prose and session material** for interpreted intent:
32+
33+
- Markdown docs and design notes
34+
- issue, PR, and review discussions
35+
- agent prompts and session summaries
36+
- manual decisions that are not encoded in scripts yet
37+
2338
Use **`.rabbit/context.yaml`** for generated operational summary:
2439

2540
- direct-read refs
@@ -38,6 +53,8 @@ If a repo needs a compact generated summary for tooling or safe repo-scoped exec
3853

3954
If a repo needs something to be executed safely by tools, keep that in a script or manifest rather than only in prose docs.
4055

56+
When both structured and prose sources exist, `dev.kit` should parse the structured source first and use prose to explain intent, repair guidance, or open decisions. That keeps automation deterministic while still preserving the human and agent context behind the repo design.
57+
4158
## Repair loop
4259

4360
1. `dev.kit repo` detects a gap or weak contract

lib/commands/env.sh

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,76 @@
22

33
# @description: Inspect environment tools and dev.kit usage config
44

5+
dev_kit_env_workflow_status() {
6+
local missing_tools=""
7+
local disabled_tools=""
8+
local disabled_credentials=""
9+
10+
missing_tools="$(dev_kit_env_missing_base_tools)"
11+
disabled_tools="$(dev_kit_env_config_list "disabled_tools")"
12+
disabled_credentials="$(dev_kit_env_config_list "disabled_credentials")"
13+
14+
if [ -n "$missing_tools" ]; then
15+
printf '%s' "blocked"
16+
return 0
17+
fi
18+
19+
if [ -n "$disabled_tools" ] || [ -n "$disabled_credentials" ]; then
20+
printf '%s' "customized"
21+
return 0
22+
fi
23+
24+
printf '%s' "ready"
25+
}
26+
27+
dev_kit_env_workflow_step_summaries() {
28+
local config_path=""
29+
30+
config_path="$(dev_kit_env_config_path)"
31+
printf '%s\n' "Detect local tools and auth capabilities."
32+
printf '%s\n' "Resolve repo-facing capabilities from the current machine."
33+
if [ -f "$config_path" ]; then
34+
printf '%s\n' "Review environment config overrides at ${config_path}."
35+
else
36+
printf '%s\n' "Create ${config_path} with dev.kit env --config when overrides are needed."
37+
fi
38+
}
39+
40+
dev_kit_env_workflow_job_json() {
41+
local config_path=""
42+
local disabled_tools=""
43+
local disabled_credentials=""
44+
local missing_tools=""
45+
local workflow_status=""
46+
local config_status="ready"
47+
48+
config_path="$(dev_kit_env_config_path)"
49+
disabled_tools="$(dev_kit_env_config_list "disabled_tools")"
50+
disabled_credentials="$(dev_kit_env_config_list "disabled_credentials")"
51+
missing_tools="$(dev_kit_env_missing_base_tools)"
52+
workflow_status="$(dev_kit_env_workflow_status)"
53+
54+
if [ -n "$disabled_tools" ] || [ -n "$disabled_credentials" ]; then
55+
config_status="customized"
56+
fi
57+
58+
printf '{ "id": "env", "label": "Resolve local environment", "command": "dev.kit env", "status": "%s", "steps": [' \
59+
"$(dev_kit_json_escape "$workflow_status")"
60+
printf '{ "id": "detect_tools", "type": "inspect", "label": "Detect local tools", "status": "%s", "missing_required": %s, "tools": %s }, ' \
61+
"$(if [ -n "$missing_tools" ]; then printf 'blocked'; else printf 'ready'; fi)" \
62+
"$(printf '%s' "$missing_tools" | tr ' ' '\n' | awk 'NF' | dev_kit_lines_to_json_array)" \
63+
"$(dev_kit_env_tools_json)"
64+
printf '{ "id": "resolve_capabilities", "type": "inspect", "label": "Resolve capabilities from the current machine", "status": "ready", "capabilities": %s }, ' \
65+
"$(dev_kit_global_context_capabilities_json)"
66+
printf '{ "id": "review_config", "type": "read", "label": "Review environment config overrides", "status": "%s", "path": "%s", "exists": %s, "disabled_tools": %s, "disabled_credentials": %s }' \
67+
"$(dev_kit_json_escape "$config_status")" \
68+
"$(dev_kit_json_escape "$config_path")" \
69+
"$([ -f "$config_path" ] && printf 'true' || printf 'false')" \
70+
"$(printf '%s' "$disabled_tools" | dev_kit_lines_to_json_array)" \
71+
"$(printf '%s' "$disabled_credentials" | dev_kit_lines_to_json_array)"
72+
printf '] }'
73+
}
74+
575
dev_kit_cmd_env() {
676
local format="${1:-text}"
777
local manage_config=0
@@ -35,6 +105,7 @@ dev_kit_cmd_env() {
35105
printf '{\n'
36106
printf ' "command": "env",\n'
37107
printf ' "home": "%s",\n' "$(dev_kit_json_escape "$DEV_KIT_HOME")"
108+
printf ' "workflow": { "id": "dev-kit", "label": "Normalize repo and environment", "jobs": [%s] },\n' "$(dev_kit_env_workflow_job_json)"
38109
printf ' "tools": %s,\n' "$(dev_kit_env_tools_json)"
39110
printf ' "capabilities": %s,\n' "$(dev_kit_global_context_capabilities_json)"
40111
printf ' "config": {\n'
@@ -49,6 +120,13 @@ dev_kit_cmd_env() {
49120

50121
dev_kit_output_title "dev.kit env"
51122

123+
dev_kit_output_section "workflow"
124+
dev_kit_output_row "job" "env"
125+
dev_kit_output_row "status" "$(dev_kit_env_workflow_status)"
126+
dev_kit_output_list_from_lines <<EOF
127+
$(dev_kit_env_workflow_step_summaries)
128+
EOF
129+
52130
local _env_line _env_cat _env_val _prev_cat=""
53131
while IFS= read -r _env_line; do
54132
[ -n "$_env_line" ] || continue

lib/commands/repo.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ dev_kit_cmd_repo() {
4545
local actions_json=""
4646
local context_yaml_path=""
4747
local gap_lines=""
48+
local workflow_status=""
49+
local workflow_context_status=""
4850

4951
local force_resolve=0
5052
local repo_soft_timeout="${DEV_KIT_REPO_SOFT_TIMEOUT:-15}"
@@ -76,12 +78,18 @@ dev_kit_cmd_repo() {
7678
local gap_count
7779
gap_count="$(printf '%s\n' "$gaps_json" | grep -c '"factor"' 2>/dev/null || true)"
7880
gap_count="${gap_count:-0}"
81+
workflow_status="$(dev_kit_repo_workflow_status "$repo_dir" "$gap_count")"
7982
actions_json="$(dev_kit_repo_actions_json "$gap_count")"
8083

8184
# JSON mode: compute everything up front then emit template
8285
if [ "$format" = "json" ]; then
8386
if [ "$mode" = "write" ]; then
8487
dev_kit_context_yaml_write "$repo_dir" "$force_resolve" >/dev/null
88+
workflow_context_status="current"
89+
elif [ -f "$context_yaml_path" ]; then
90+
workflow_context_status="existing"
91+
else
92+
workflow_context_status="missing"
8593
fi
8694
dev_kit_template_render "repo.json" \
8795
"command=repo" \
@@ -93,6 +101,7 @@ dev_kit_cmd_repo() {
93101
"factors=$(dev_kit_repo_factor_summary_json "$repo_dir")" \
94102
"gaps=$gaps_json" \
95103
"actions=$actions_json" \
104+
"workflow={ \"id\": \"dev-kit\", \"label\": \"Normalize repo and environment\", \"jobs\": [$(dev_kit_repo_workflow_job_json "$repo_dir" "$workflow_status" "$mode" "$workflow_context_status" "$gap_count")] }" \
96105
"context=$(dev_kit_json_escape "$context_yaml_path")" \
97106
"dependencies=$(dev_kit_deps_json "$repo_dir")" \
98107
"recommended_repos=$(dev_kit_repo_recommended_repos_json)"
@@ -109,6 +118,13 @@ dev_kit_cmd_repo() {
109118

110119
dev_kit_output_summary "${repo_name}${archetype} • mode: ${mode}"
111120

121+
dev_kit_output_section "workflow"
122+
dev_kit_output_row "job" "repo"
123+
dev_kit_output_row "status" "$workflow_status"
124+
dev_kit_output_list_from_lines <<EOF
125+
$(dev_kit_repo_workflow_step_summaries "$repo_dir")
126+
EOF
127+
112128
# ── Priority refs — what to read first ─────────────────────────────────────
113129
local priority_refs first_ref second_ref
114130
priority_refs="$(dev_kit_repo_priority_refs "$repo_dir")"

0 commit comments

Comments
 (0)