lightcone-cli 0.2.0__py3-none-any.whl
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.
- lightcone/cli/__init__.py +16 -0
- lightcone/cli/claude/lightcone/agents/lc-extractor.md +114 -0
- lightcone/cli/claude/lightcone/guides/astra-reference.md +290 -0
- lightcone/cli/claude/lightcone/guides/lightcone-cli-reference.md +75 -0
- lightcone/cli/claude/lightcone/guides/ui-brand.md +86 -0
- lightcone/cli/claude/lightcone/hooks/langfuse_git_commit_hook.py +303 -0
- lightcone/cli/claude/lightcone/hooks/langfuse_hook.py +894 -0
- lightcone/cli/claude/lightcone/hooks/langfuse_prepare_commit_msg.py +142 -0
- lightcone/cli/claude/lightcone/hooks/langfuse_session_init_hook.py +83 -0
- lightcone/cli/claude/lightcone/hooks/langfuse_utils.py +457 -0
- lightcone/cli/claude/lightcone/scripts/activate-venv.sh +44 -0
- lightcone/cli/claude/lightcone/scripts/check-lc-run.sh +140 -0
- lightcone/cli/claude/lightcone/scripts/session-start.sh +140 -0
- lightcone/cli/claude/lightcone/scripts/validate-on-save.sh +77 -0
- lightcone/cli/claude/lightcone/skills/lc-build/SKILL.md +92 -0
- lightcone/cli/claude/lightcone/skills/lc-build/assets/loop-prompt.md +92 -0
- lightcone/cli/claude/lightcone/skills/lc-build/scripts/setup-lc-build.sh +240 -0
- lightcone/cli/claude/lightcone/skills/lc-feedback/SKILL.md +94 -0
- lightcone/cli/claude/lightcone/skills/lc-migrate/SKILL.md +98 -0
- lightcone/cli/claude/lightcone/skills/lc-new/SKILL.md +183 -0
- lightcone/cli/claude/lightcone/skills/lc-verify/SKILL.md +53 -0
- lightcone/cli/claude/lightcone/templates/CLAUDE.md +32 -0
- lightcone/cli/commands.py +2327 -0
- lightcone/cli/plugin.py +34 -0
- lightcone/engine/__init__.py +42 -0
- lightcone/engine/assets.py +418 -0
- lightcone/engine/container.py +370 -0
- lightcone/engine/io_manager.py +27 -0
- lightcone/engine/runner.py +1017 -0
- lightcone/engine/site_registry.py +142 -0
- lightcone/engine/status.py +135 -0
- lightcone/engine/targets.py +68 -0
- lightcone/engine/tree.py +245 -0
- lightcone/eval/__init__.py +25 -0
- lightcone/eval/build.py +148 -0
- lightcone/eval/cli.py +176 -0
- lightcone/eval/graders.py +192 -0
- lightcone/eval/harness.py +265 -0
- lightcone/eval/models.py +117 -0
- lightcone/eval/report.py +214 -0
- lightcone/eval/sandbox.py +394 -0
- lightcone_cli-0.2.0.dist-info/METADATA +16 -0
- lightcone_cli-0.2.0.dist-info/RECORD +46 -0
- lightcone_cli-0.2.0.dist-info/WHEEL +4 -0
- lightcone_cli-0.2.0.dist-info/entry_points.txt +2 -0
- lightcone_cli-0.2.0.dist-info/licenses/LICENSE +29 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Setup script for lc-build skill
|
|
3
|
+
# Two modes: --validate (pre-planning) and --activate (post-approval)
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
MODE=""
|
|
8
|
+
UNIVERSE="baseline"
|
|
9
|
+
MAX_ITERATIONS=25
|
|
10
|
+
MAX_ITERATIONS_EXPLICIT=false
|
|
11
|
+
while [[ $# -gt 0 ]]; do
|
|
12
|
+
case "$1" in
|
|
13
|
+
--validate) MODE="validate"; shift ;;
|
|
14
|
+
--activate) MODE="activate"; shift ;;
|
|
15
|
+
--resume) MODE="resume"; shift ;;
|
|
16
|
+
--universe)
|
|
17
|
+
UNIVERSE="$2"
|
|
18
|
+
shift 2
|
|
19
|
+
;;
|
|
20
|
+
--max-iterations)
|
|
21
|
+
MAX_ITERATIONS="$2"
|
|
22
|
+
MAX_ITERATIONS_EXPLICIT=true
|
|
23
|
+
shift 2
|
|
24
|
+
;;
|
|
25
|
+
*)
|
|
26
|
+
echo "Unknown argument: $1" >&2
|
|
27
|
+
echo "Usage: setup-lc-build.sh --validate|--activate|--resume --universe NAME --max-iterations N" >&2
|
|
28
|
+
exit 1
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
if [[ -z "$MODE" ]]; then
|
|
34
|
+
echo "Error: must specify --validate or --activate" >&2
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Validate universe name — must be safe for sed substitution and file paths
|
|
39
|
+
if [[ ! "$UNIVERSE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
40
|
+
echo "Error: Universe name must contain only letters, numbers, underscores, and hyphens." >&2
|
|
41
|
+
echo "Got: '${UNIVERSE}'" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# ─── Validate mode ───────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
if [[ "$MODE" == "validate" ]]; then
|
|
48
|
+
|
|
49
|
+
# Check astra.yaml exists
|
|
50
|
+
if [[ ! -f "astra.yaml" ]]; then
|
|
51
|
+
echo "Error: astra.yaml not found in $(pwd)"
|
|
52
|
+
echo "Run /lc-new to create an analysis specification first."
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Check astra CLI available
|
|
57
|
+
if ! command -v astra &>/dev/null; then
|
|
58
|
+
echo "Error: astra CLI not found. Run: pip install astra"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Validate spec
|
|
63
|
+
echo "Validating astra.yaml..."
|
|
64
|
+
validation_output=$(astra validate astra.yaml 2>&1) || {
|
|
65
|
+
echo "Validation failed:"
|
|
66
|
+
echo "$validation_output"
|
|
67
|
+
echo ""
|
|
68
|
+
echo "Fix validation errors before building."
|
|
69
|
+
exit 1
|
|
70
|
+
}
|
|
71
|
+
echo "Validation: passed"
|
|
72
|
+
|
|
73
|
+
# Check/create universe
|
|
74
|
+
if [[ ! -f "universes/${UNIVERSE}.yaml" ]]; then
|
|
75
|
+
echo "Universe '${UNIVERSE}' does not exist. Creating..."
|
|
76
|
+
astra universe generate -n "$UNIVERSE" 2>&1
|
|
77
|
+
echo "Universe created: universes/${UNIVERSE}.yaml"
|
|
78
|
+
else
|
|
79
|
+
echo "Universe: ${UNIVERSE} (exists)"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# Check lc CLI
|
|
83
|
+
if ! command -v lc &>/dev/null; then
|
|
84
|
+
echo "Warning: lc CLI not found. Materialization commands will fail."
|
|
85
|
+
echo "Run: pip install lightcone-cli"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Summary
|
|
89
|
+
echo ""
|
|
90
|
+
echo "Ready to plan build for universe: ${UNIVERSE}"
|
|
91
|
+
echo "Max iterations: ${MAX_ITERATIONS}"
|
|
92
|
+
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ─── Activate mode ───────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
if [[ "$MODE" == "activate" ]]; then
|
|
99
|
+
|
|
100
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
101
|
+
PROMPT_TEMPLATE="${SCRIPT_DIR}/../assets/loop-prompt.md"
|
|
102
|
+
|
|
103
|
+
# Check template exists
|
|
104
|
+
if [[ ! -f "$PROMPT_TEMPLATE" ]]; then
|
|
105
|
+
echo "Error: loop-prompt.md template not found at ${PROMPT_TEMPLATE}" >&2
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# Check build plan exists
|
|
110
|
+
if [[ ! -f ".lightcone/plans/build-plan-${UNIVERSE}.md" ]]; then
|
|
111
|
+
echo "Warning: No build plan found at .lightcone/plans/build-plan-${UNIVERSE}.md"
|
|
112
|
+
echo "The loop will proceed without a plan."
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Fail hard if loop already active — don't silently overwrite a live loop
|
|
116
|
+
if [[ -f ".claude/ralph-loop.local.md" ]]; then
|
|
117
|
+
existing_iter=$(grep '^iteration:' .claude/ralph-loop.local.md 2>/dev/null | awk '{print $2}' || echo "?")
|
|
118
|
+
echo "Error: An active loop state file already exists (iteration ${existing_iter})." >&2
|
|
119
|
+
echo " To resume the interrupted loop: setup-lc-build.sh --resume" >&2
|
|
120
|
+
echo " To start fresh: delete .claude/ralph-loop.local.md first, then re-run --activate" >&2
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# Ensure ralph-loop plugin is available
|
|
125
|
+
# Update MARKETPLACE_URL if the official plugin repository moves.
|
|
126
|
+
MARKETPLACE_URL="https://github.com/anthropics/claude-plugins-official.git"
|
|
127
|
+
RALPH_PLUGIN="$HOME/.claude/plugins/marketplaces/claude-plugins-official/plugins/ralph-loop"
|
|
128
|
+
MARKETPLACE="$HOME/.claude/plugins/marketplaces/claude-plugins-official"
|
|
129
|
+
|
|
130
|
+
if [[ ! -d "$RALPH_PLUGIN" ]]; then
|
|
131
|
+
echo "ralph-loop plugin not found. Attempting to install..."
|
|
132
|
+
|
|
133
|
+
if [[ -d "$MARKETPLACE/.git" ]]; then
|
|
134
|
+
# Marketplace exists but plugin missing — pull latest
|
|
135
|
+
echo "Updating plugin marketplace..."
|
|
136
|
+
git -C "$MARKETPLACE" pull --ff-only 2>&1 || true
|
|
137
|
+
elif [[ ! -d "$MARKETPLACE" ]]; then
|
|
138
|
+
# No marketplace at all — clone it
|
|
139
|
+
echo "Cloning plugin marketplace..."
|
|
140
|
+
mkdir -p "$HOME/.claude/plugins/marketplaces"
|
|
141
|
+
git clone "$MARKETPLACE_URL" "$MARKETPLACE" 2>&1 || true
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Check again after update/clone
|
|
145
|
+
if [[ ! -d "$RALPH_PLUGIN" ]]; then
|
|
146
|
+
echo ""
|
|
147
|
+
echo "Error: ralph-loop plugin could not be installed." >&2
|
|
148
|
+
echo "The stop hook is required for /lc-build to loop." >&2
|
|
149
|
+
echo "" >&2
|
|
150
|
+
echo "Manual install: /plugin install ralph-loop@claude-plugins-official" >&2
|
|
151
|
+
# Clean up — don't leave a state file that traps the user
|
|
152
|
+
rm -f .claude/ralph-loop.local.md
|
|
153
|
+
exit 1
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
echo "ralph-loop plugin found after update."
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# Verify the stop hook exists within the plugin
|
|
160
|
+
if [[ ! -f "$RALPH_PLUGIN/hooks/stop-hook.sh" ]]; then
|
|
161
|
+
echo "Error: ralph-loop plugin is present but hooks/stop-hook.sh is missing." >&2
|
|
162
|
+
echo "The plugin may be corrupted. Try: /plugin install ralph-loop@claude-plugins-official" >&2
|
|
163
|
+
exit 1
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
# Template the prompt
|
|
167
|
+
prompt_body=$(sed "s/{{UNIVERSE}}/${UNIVERSE}/g" "$PROMPT_TEMPLATE")
|
|
168
|
+
|
|
169
|
+
# Create state file
|
|
170
|
+
mkdir -p .claude
|
|
171
|
+
cat > .claude/ralph-loop.local.md <<EOF
|
|
172
|
+
---
|
|
173
|
+
active: true
|
|
174
|
+
iteration: 1
|
|
175
|
+
max_iterations: ${MAX_ITERATIONS}
|
|
176
|
+
completion_promise: "BUILD_COMPLETE"
|
|
177
|
+
session_id: ${CLAUDE_CODE_SESSION_ID:-}
|
|
178
|
+
universe: ${UNIVERSE}
|
|
179
|
+
started_at: "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
${prompt_body}
|
|
183
|
+
EOF
|
|
184
|
+
|
|
185
|
+
echo "Loop activated for universe: ${UNIVERSE}"
|
|
186
|
+
echo " State file: .claude/ralph-loop.local.md"
|
|
187
|
+
echo " Max iterations: ${MAX_ITERATIONS}"
|
|
188
|
+
echo " Completion promise: BUILD_COMPLETE"
|
|
189
|
+
echo ""
|
|
190
|
+
echo "The stop hook will re-inject the build prompt on each exit."
|
|
191
|
+
echo "To cancel: /cancel-ralph"
|
|
192
|
+
|
|
193
|
+
exit 0
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
# ─── Resume mode ────────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
if [[ "$MODE" == "resume" ]]; then
|
|
199
|
+
|
|
200
|
+
RALPH_STATE_FILE=".claude/ralph-loop.local.md"
|
|
201
|
+
|
|
202
|
+
if [[ ! -f "$RALPH_STATE_FILE" ]]; then
|
|
203
|
+
echo "No active loop to resume (state file not found)."
|
|
204
|
+
echo "Run /lc-build to start a new build."
|
|
205
|
+
exit 1
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
# Read current state from file
|
|
209
|
+
CURRENT_ITER=$(grep '^iteration:' "$RALPH_STATE_FILE" | awk '{print $2}')
|
|
210
|
+
OLD_SESSION=$(grep '^session_id:' "$RALPH_STATE_FILE" | awk '{print $2}')
|
|
211
|
+
CURRENT_MAX=$(grep '^max_iterations:' "$RALPH_STATE_FILE" | awk '{print $2}')
|
|
212
|
+
|
|
213
|
+
# Read universe from dedicated frontmatter field
|
|
214
|
+
LOOP_UNIVERSE=$(grep '^universe:' "$RALPH_STATE_FILE" | awk '{print $2}')
|
|
215
|
+
|
|
216
|
+
# Update session_id to claim this loop for the current session
|
|
217
|
+
TEMP_FILE="${RALPH_STATE_FILE}.tmp.$$"
|
|
218
|
+
sed "s/^session_id: .*/session_id: ${CLAUDE_CODE_SESSION_ID:-}/" "$RALPH_STATE_FILE" > "$TEMP_FILE"
|
|
219
|
+
|
|
220
|
+
# If --max-iterations was explicitly passed, update it in the state file
|
|
221
|
+
if [[ "$MAX_ITERATIONS_EXPLICIT" == "true" ]]; then
|
|
222
|
+
sed -i "s/^max_iterations: .*/max_iterations: ${MAX_ITERATIONS}/" "$TEMP_FILE"
|
|
223
|
+
CURRENT_MAX="${MAX_ITERATIONS}"
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
mv "$TEMP_FILE" "$RALPH_STATE_FILE"
|
|
227
|
+
|
|
228
|
+
# Compute remaining iterations
|
|
229
|
+
REMAINING=$(( ${CURRENT_MAX:-0} - ${CURRENT_ITER:-1} + 1 ))
|
|
230
|
+
|
|
231
|
+
echo "Resumed loop for universe: ${LOOP_UNIVERSE:-unknown}"
|
|
232
|
+
echo " Continuing from iteration: ${CURRENT_ITER:-?} / ${CURRENT_MAX:-?}"
|
|
233
|
+
echo " Remaining iterations: ${REMAINING}"
|
|
234
|
+
echo " Session updated: ${OLD_SESSION:-<unset>} -> ${CLAUDE_CODE_SESSION_ID:-<unset>}"
|
|
235
|
+
if [[ "$MAX_ITERATIONS_EXPLICIT" == "true" ]]; then
|
|
236
|
+
echo " Max iterations updated to: ${MAX_ITERATIONS}"
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
exit 0
|
|
240
|
+
fi
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lc-feedback
|
|
3
|
+
description: >
|
|
4
|
+
File a bug report from the current session. Use when something breaks:
|
|
5
|
+
/lc-feedback <description of what went wrong>
|
|
6
|
+
allowed-tools: Bash(gh:*), Bash(python:*), Bash(uname:*), AskUserQuestion
|
|
7
|
+
argument-hint: "<what went wrong>"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# /lc-feedback
|
|
11
|
+
|
|
12
|
+
File a bug report against the right Lightcone repo based on the current session.
|
|
13
|
+
|
|
14
|
+
Be fast. The user is in the middle of work and wants to get back to it.
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
Run `gh auth status` silently. If it fails:
|
|
19
|
+
|
|
20
|
+
> GitHub CLI is not authenticated. Run `gh auth login`, then try again.
|
|
21
|
+
|
|
22
|
+
Stop.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Step 1: Description
|
|
27
|
+
|
|
28
|
+
The user should have provided a description inline (e.g., `/lc-feedback pipeline dies on second output`). If they didn't, ask briefly:
|
|
29
|
+
|
|
30
|
+
**What went wrong?**
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Step 2: Draft and Confirm
|
|
35
|
+
|
|
36
|
+
Triage the repo from context:
|
|
37
|
+
- **ASTRA** — `astra` CLI, schema validation, YAML parsing, helpers
|
|
38
|
+
- **lightcone-cli** — `lc` CLI, Dagster execution, recipes, container builds, scaffolding, skills, telemetry hooks
|
|
39
|
+
|
|
40
|
+
Default to **lightcone-cli** if ambiguous.
|
|
41
|
+
|
|
42
|
+
Collect versions silently:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
python3 -c "import astra; print(astra.__version__)" 2>/dev/null || echo "n/a"
|
|
46
|
+
python3 -c "import lightcone.cli; print(lightcone.cli.__version__)" 2>/dev/null || echo "n/a"
|
|
47
|
+
python3 --version 2>&1
|
|
48
|
+
uname -s -r
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Show the user a single confirmation message with the target repo, title, and body. Use `AskUserQuestion` with options "File it" / "Let me edit". The issue body format:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
## What happened
|
|
55
|
+
|
|
56
|
+
[1-3 sentences combining user description + session context]
|
|
57
|
+
|
|
58
|
+
## Error
|
|
59
|
+
|
|
60
|
+
[Trimmed error/traceback from session, if any]
|
|
61
|
+
|
|
62
|
+
## Reproduction
|
|
63
|
+
|
|
64
|
+
[Brief steps from session context]
|
|
65
|
+
|
|
66
|
+
## Environment
|
|
67
|
+
|
|
68
|
+
- ASTRA: [version]
|
|
69
|
+
- lightcone-cli: [version]
|
|
70
|
+
- Python: [version]
|
|
71
|
+
- OS: [os]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Omit sections that don't apply (e.g., no Error section if there was no traceback).
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Step 3: File
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
gh issue create --repo LightconeResearch/<REPO> --title "<TITLE>" --label "beta-feedback" --body "<BODY>"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If it fails due to the label not existing, retry without `--label`. Print the issue URL.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Rules
|
|
89
|
+
|
|
90
|
+
- **Be fast** — minimize back-and-forth, one confirmation then file
|
|
91
|
+
- **Read-only** — never modify project files
|
|
92
|
+
- **Trim aggressively** — only the relevant portion of errors, not full files
|
|
93
|
+
- **No sensitive data** — strip absolute paths, credentials, tokens
|
|
94
|
+
- **Don't editorialize** — report what happened, don't speculate on fixes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lc-migrate
|
|
3
|
+
description: Migrate an existing project into ASTRA / lightcone-cli. Scans code, generates astra.yaml, parameterizes decisions, and runs until outputs materialize. Use after `lc init . --existing-project`. Triggers on "migrate", "convert", "existing project".
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep, Bash(astra:*), Bash(lc:*), Bash(python:*), Bash(pip:*), Bash(git:*), Bash(mkdir:*), Bash(ls:*), Agent, AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /lc-migrate
|
|
8
|
+
|
|
9
|
+
End-to-end migration: scan existing code, generate the ASTRA spec, parameterize decisions in the code, and run until everything materializes. The user's existing logic stays intact — changes should be minimal.
|
|
10
|
+
|
|
11
|
+
## References
|
|
12
|
+
|
|
13
|
+
- [ASTRA Reference](../../guides/astra-reference.md) -- spec structure, decision identification, recipes, universes
|
|
14
|
+
|
|
15
|
+
## Phase 1: Scan & Spec
|
|
16
|
+
|
|
17
|
+
Spawn an Explore subagent to scan the project:
|
|
18
|
+
|
|
19
|
+
First, read the Decisions section of [ASTRA Reference](../../guides/astra-reference.md), then spawn an Explore subagent. Include the decision criteria in the prompt so the subagent can classify candidates:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Agent(subagent_type="Explore", prompt="""
|
|
23
|
+
Scan this project thoroughly and return a structured inventory.
|
|
24
|
+
|
|
25
|
+
For every script and notebook, report:
|
|
26
|
+
- File path
|
|
27
|
+
- What it does (read the code, don't guess)
|
|
28
|
+
- What files it reads (data, configs, other scripts' outputs)
|
|
29
|
+
- What files it writes (results, plots, models, etc.)
|
|
30
|
+
- Hardcoded analytical choices: magic numbers, commented alternatives,
|
|
31
|
+
method-selecting branches, config dicts. Include file, line number,
|
|
32
|
+
current value, and what it controls.
|
|
33
|
+
- How it's currently invoked (argparse, config file, nothing)
|
|
34
|
+
|
|
35
|
+
Also report:
|
|
36
|
+
- Dependencies (requirements.txt, pyproject.toml, environment.yml, etc.)
|
|
37
|
+
- Data files present in the project
|
|
38
|
+
- Any existing container setup (Dockerfile, Containerfile)
|
|
39
|
+
|
|
40
|
+
Return the results as a markdown table:
|
|
41
|
+
| Script | Purpose | Reads | Writes | Hardcoded choices |
|
|
42
|
+
|
|
43
|
+
And a separate list of ALL candidate decisions with file:line references.
|
|
44
|
+
Err on the side of completeness — include anything that could plausibly
|
|
45
|
+
be an analytical choice. The orchestrator will filter down later.
|
|
46
|
+
|
|
47
|
+
For reference, here are the decision criteria for classifying candidates:
|
|
48
|
+
<decision-criteria>
|
|
49
|
+
{paste Decisions section from astra-reference.md here}
|
|
50
|
+
</decision-criteria>
|
|
51
|
+
""")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Write the scan results to `CLAUDE.md` under Analysis Context as a script inventory, then draft `astra.yaml` from the scan results following the spec structure documented in `.claude/guides/astra-reference.md`. Use the decision criteria from [ASTRA Reference](../../guides/astra-reference.md) to filter the subagent's candidate decisions down to only true analytical choices — most hardcoded values are implementation details, not decisions. Use current hardcoded values as defaults.
|
|
55
|
+
|
|
56
|
+
Include `recipe:` blocks on each output pointing to the script that produces it. Also generate `universes/baseline.yaml` with all defaults matching the current hardcoded values (so the first run reproduces existing behavior).
|
|
57
|
+
|
|
58
|
+
Write to `astra.yaml` and `universes/baseline.yaml`, then validate: `astra validate astra.yaml`. Fix any errors.
|
|
59
|
+
|
|
60
|
+
Use `AskUserQuestion` to ask the user to review the spec — they can open `astra.yaml` directly or right-click it and open in lightcone-ui. Wait for confirmation before proceeding to implementation.
|
|
61
|
+
|
|
62
|
+
## Phase 2: Implement
|
|
63
|
+
|
|
64
|
+
Parameterize the code so decisions can be varied across universes. The goal is minimal changes to user code. Use your best judgement for the approach — the options below are not exhaustive:
|
|
65
|
+
|
|
66
|
+
**For scripts with hardcoded values:** Add argparse (or extend existing argument parsing) and replace hardcoded values with the parsed args. This is the simplest case.
|
|
67
|
+
|
|
68
|
+
**For notebooks:** Move the `.ipynb` to `notebooks/` (preserving it as reference), then create a `.py` script that does the parameterized version. The recipe points to the new script.
|
|
69
|
+
|
|
70
|
+
**For config-file-driven projects:** Create a thin wrapper script that accepts ASTRA decision args, writes/updates the config file, then calls the original entry point. The user's config-driven code stays untouched.
|
|
71
|
+
|
|
72
|
+
**Dependencies:** Check that `requirements.txt` includes all packages the code imports. If one doesn't exist, create it. If it's incomplete, add missing deps.
|
|
73
|
+
|
|
74
|
+
Whatever approach you use:
|
|
75
|
+
|
|
76
|
+
- **Don't refactor, restructure, or improve the code.** Just add the parameter plumbing.
|
|
77
|
+
- **Underscore convention:** Decision IDs use underscores in `astra.yaml` (`outlier_sigma`). lightcone-cli passes `--outlier_sigma`. Argument parsing must match.
|
|
78
|
+
- **Update output paths** to write to `results/{universe}/{output_id}.ext` following the convention in `CLAUDE.md`.
|
|
79
|
+
- **Update recipes** in `astra.yaml` if the entry point or command changed.
|
|
80
|
+
|
|
81
|
+
## Phase 3: Run & Debug
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
lc run --universe baseline
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If it fails, read the error, fix it, and retry. Iterate until `lc status` shows all outputs as `ok`.
|
|
88
|
+
|
|
89
|
+
If the scan found existing results elsewhere in the project, compare them against the new outputs in `results/baseline/` to verify the migration preserved behavior.
|
|
90
|
+
|
|
91
|
+
Then validate: `astra validate astra.yaml`. Present summary to user.
|
|
92
|
+
|
|
93
|
+
## Rules
|
|
94
|
+
|
|
95
|
+
- **Minimal changes.** Do not refactor, rename, reorganize, or "improve" existing code.
|
|
96
|
+
- **Don't guess.** Read every script before making claims about what it does.
|
|
97
|
+
- **Filter decisions aggressively.** Most hardcoded values are implementation details, not analytical choices.
|
|
98
|
+
- **Preserve behavior.** The baseline universe with default values must reproduce the original behavior exactly.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lc-new
|
|
3
|
+
description: Create a new ASTRA analysis project with integrated literature support. Scope the research question through conversation, structure outputs and decisions, search for and extract evidence from scientific papers, and build a complete astra.yaml specification. Use when starting a new analysis, when the user says "new project", "new analysis", or "scope". Triggers on "new", "scope", "research question", "start analysis".
|
|
4
|
+
allowed-tools: Read, Write(astra.yaml), Write(universes/*), Write(CLAUDE.md), Edit(astra.yaml), Edit(universes/*), Edit(CLAUDE.md), Glob, Grep, Bash(astra:*), Bash(lc:*), Bash(mkdir:*), Bash(echo:*), WebSearch, WebFetch, AskUserQuestion, Task
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /lc-new
|
|
8
|
+
|
|
9
|
+
Create a new ASTRA analysis project through conversation. Build the spec iteratively -- write to `astra.yaml` after each phase so the user sees progress. Literature search and decision identification happen in distinct phases -- talk first, then extract papers, then identify decisions informed by both conversation and literature.
|
|
10
|
+
|
|
11
|
+
## References
|
|
12
|
+
|
|
13
|
+
- [ASTRA Reference](../../guides/astra-reference.md) -- spec structure, decision identification, recipes, universes
|
|
14
|
+
- [UI Brand](../../guides/ui-brand.md) -- visual formatting patterns
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
1. Read `astra.yaml` if it exists (to understand context or avoid overwriting)
|
|
19
|
+
2. Note the analysis directory for later
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Phase 1: Research Question
|
|
24
|
+
|
|
25
|
+
Stage banner: RESEARCH QUESTION
|
|
26
|
+
|
|
27
|
+
> "What are you trying to learn? Describe the question in your own words."
|
|
28
|
+
|
|
29
|
+
Then sharpen:
|
|
30
|
+
- "What would a clear answer look like?" (sharpens the description)
|
|
31
|
+
- "Why does this matter?" (context for decisions)
|
|
32
|
+
|
|
33
|
+
**Write to astra.yaml immediately** with `version`, `name`, `description`. This gives the user something visible right away.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Phase 2: Analysis Structure
|
|
38
|
+
|
|
39
|
+
Stage banner: ANALYSIS STRUCTURE
|
|
40
|
+
|
|
41
|
+
> "Walk me through your analysis step by step. What goes in, what comes out at the end?"
|
|
42
|
+
|
|
43
|
+
**Guidance on sub-analyses:** Analyses should only be split into multiple sub-analyses if each sub analysis genuinely has materially different inputs and outputs, and if the scope may be too broad if there is just one analysis; we overall want a sub-analysis to feel like it should genuinely be a self-contained product. For example, training + evaluation would typically be one analysis, because the product would be the trained and validated neural network estimator. When in doubt, opt for a single analysis at this stage. If it does need to be multi-stage, ask the user for confirmation and how to split it. For multi-stage analyses, make sure you confirm stage boundaries. See `.claude/guides/astra-reference.md` for YAML structure and sub-analysis guidance.
|
|
44
|
+
|
|
45
|
+
**One output per output.** Each output should be a single metric, a single plot, or a single artifact. Do not bundle multiple metrics into one output (e.g., "performance_metrics" containing accuracy, F1, and AUC). Each of those is its own output. Same for plots -- one figure per output.
|
|
46
|
+
|
|
47
|
+
**Update astra.yaml** with `inputs` and `outputs` (extending the spec from Phase 1).
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Phase 3: Deep Dive
|
|
52
|
+
|
|
53
|
+
Stage banner: DEEP DIVE -- [SECTION NAME]
|
|
54
|
+
|
|
55
|
+
Ask the user if they want to do a literature deep dive for this section. If not, skip straight to decision identification.
|
|
56
|
+
|
|
57
|
+
### Paper Collection
|
|
58
|
+
|
|
59
|
+
Ask if the user has specific papers they want to look into. Also search with WebSearch for highly relevant papers -- keep it limited, only papers that directly bear on the analysis. Use AskUserQuestion to present the list with a one-line description of each paper and why it's relevant. The user can check off which ones to extract and add any others.
|
|
60
|
+
|
|
61
|
+
### Extraction
|
|
62
|
+
|
|
63
|
+
For each approved paper: `astra paper add <doi>`, `astra paper path <doi>`, then spawn one `lc-extractor` agent per paper. The agent definition already contains extraction instructions, output format, and verification logic -- you just fill in the paper-specific context.
|
|
64
|
+
|
|
65
|
+
**Spawning each agent:** Use `Agent(subagent_type="lc-extractor", prompt="...")`. In the prompt, provide:
|
|
66
|
+
- **Analysis context**: the analysis description and decisions this paper might inform
|
|
67
|
+
- **Paper details**: DOI, version (arXiv only), PDF path (from `astra paper path`)
|
|
68
|
+
- **Target decisions**: each decision ID, label, and options with descriptions
|
|
69
|
+
- **Timestamp**: current time in ISO 8601
|
|
70
|
+
|
|
71
|
+
The agent type is pre-configured with the user's preferred extraction model (set via `lc setup`). Spawn all in a single message (parallel). Show progress as results come in:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
✓ Ba et al. 2016 -- 3 prior insights
|
|
75
|
+
○ Wu & He 2018 (reading...)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Write extracted prior insights to astra.yaml immediately. Synthesize them by topic for the user.
|
|
79
|
+
|
|
80
|
+
### Decision Identification
|
|
81
|
+
|
|
82
|
+
Use the conversation and literature to identify decisions. Apply the decision criteria from [astra-reference.md](../../guides/astra-reference.md):
|
|
83
|
+
|
|
84
|
+
- What could be done differently and still be defensible?
|
|
85
|
+
- Where did papers disagree or compare alternatives?
|
|
86
|
+
- Where did the user express uncertainty?
|
|
87
|
+
|
|
88
|
+
Write candidate decisions to astra.yaml as a batch for user review. Keep chat output concise (summary + decision IDs), and avoid dumping full decision details in chat.
|
|
89
|
+
|
|
90
|
+
**Probe for blind spots** -- analysts over-focus on methods and neglect data handling. Probe 1-3 areas: data exclusion, variable operationalization, inference criteria.
|
|
91
|
+
|
|
92
|
+
### Decision Review
|
|
93
|
+
|
|
94
|
+
During review, confirm or set each decision's `default`, keep option structure and evidence links, and remove any decisions the user rejects.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Checkpoint
|
|
99
|
+
|
|
100
|
+
> "Anything else that should inform this analysis?"
|
|
101
|
+
|
|
102
|
+
Review the spec with the user. Update astra.yaml with any additions.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Finalize
|
|
107
|
+
|
|
108
|
+
Stage banner: FINALIZING
|
|
109
|
+
|
|
110
|
+
### Validate
|
|
111
|
+
|
|
112
|
+
1. `astra validate astra.yaml` -- fix errors, iterate until clean
|
|
113
|
+
2. If prior insights exist: `astra validate astra.yaml --verify-evidence`
|
|
114
|
+
|
|
115
|
+
### Generate Baseline Universe
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
astra universe generate -n baseline
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Populate CLAUDE.md
|
|
122
|
+
|
|
123
|
+
Read the existing `CLAUDE.md` (created by `lc init`). Replace the `## Working Notes` section with context that is NOT already visible in `astra.yaml`. The spec is the source of truth for structure, decisions, and evidence -- CLAUDE.md captures only what would be lost after `/clear`:
|
|
124
|
+
|
|
125
|
+
- **Domain Context**: important things the user explained during scoping -- data characteristics, constraints, why certain approaches were preferred. This is conversational context not captured in the spec.
|
|
126
|
+
- **Implementation Notes**: domain-specific guidance from the conversation (libraries, data formats, gotchas)
|
|
127
|
+
|
|
128
|
+
### Review with User
|
|
129
|
+
|
|
130
|
+
> "Anything you'd like to change? Otherwise the specification is ready."
|
|
131
|
+
|
|
132
|
+
If edits requested, apply, re-validate, and update CLAUDE.md.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Done
|
|
137
|
+
|
|
138
|
+
Stage banner: SPECIFICATION COMPLETE
|
|
139
|
+
|
|
140
|
+
Show summary table:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
| Section | Decisions | Outputs | Prior Insights |
|
|
144
|
+
|---------------|-----------|---------|----------|
|
|
145
|
+
| (top-level) | 3 | 2 | 5 |
|
|
146
|
+
| sub_analysis | ... | ... | ... |
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Then show a Next Up block (see ui-brand.md) with:
|
|
150
|
+
|
|
151
|
+
- Run `/clear` to free up context, then `/lc-build` to start building
|
|
152
|
+
- Or `/lc-build [description]` to guide what to focus on first (e.g. `/lc-build focus on the fitting script`)
|
|
153
|
+
- Also available: `/lc-verify`
|
|
154
|
+
|
|
155
|
+
Prompt the user to `/clear` before starting implementation. The scoping conversation consumes significant context. Everything needed to continue is captured in `astra.yaml` and `CLAUDE.md`.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Restrictions
|
|
160
|
+
|
|
161
|
+
**You are a specification agent, not an implementation agent.**
|
|
162
|
+
|
|
163
|
+
You MUST NOT write Python, R, or other implementation code.
|
|
164
|
+
|
|
165
|
+
You MUST ONLY create/modify: `astra.yaml`, `universes/*.yaml`, `CLAUDE.md` (Finalize only).
|
|
166
|
+
|
|
167
|
+
You MUST NOT fabricate quotes -- all evidence must pass `astra validate --verify-evidence`.
|
|
168
|
+
|
|
169
|
+
You MUST spawn `lc-extractor` agents for paper processing. One paper per agent. Never read a PDF in the main agent context.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Anti-Patterns
|
|
174
|
+
|
|
175
|
+
- **Waiting to write** -- Update astra.yaml after each decision crystallizes, not in bulk at the end
|
|
176
|
+
- **Accepting vague goals** -- "Analyze this data" is not a research question; push back
|
|
177
|
+
- **Method-only decisions** -- Actively probe for data handling and exclusion criteria, not just method choices
|
|
178
|
+
- **Literature as afterthought** -- Do not defer all literature to the end. Collect paper candidates during conversation (Phases 1-2) and extract them before identifying decisions (Extraction before Decision Identification in Phase 3)
|
|
179
|
+
- **Too many papers** -- ~2 papers per topic area, max 10 per section; do not try to be exhaustive
|
|
180
|
+
- **Background interruptions** -- Never spawn search or extraction subagents during conversation phases. Collect candidates first, then process them during Phase 3 Extraction
|
|
181
|
+
- **Reading PDFs in main context** -- Always delegate to subagents; PDFs consume too much context
|
|
182
|
+
- **Chat dump of decisions** -- Do not dump full candidate decision content in chat; write decisions to astra.yaml for review
|
|
183
|
+
- **Skipping verification** -- If quotes were extracted, always run `astra validate --verify-evidence`
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lc-verify
|
|
3
|
+
description: Verify that astra.yaml, code, and results are consistent. Run after building an analysis.
|
|
4
|
+
allowed-tools: Read, Glob, Grep, Bash(astra:*), Bash(lc:*), Bash(python:*), Bash(ls:*), AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /lc-verify
|
|
8
|
+
|
|
9
|
+
Verify that the spec, code, and results all agree. Default universe is `baseline` unless specified.
|
|
10
|
+
|
|
11
|
+
## Checks
|
|
12
|
+
|
|
13
|
+
### 1. Spec validation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
astra validate astra.yaml
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. Materialization status
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
lc status --universe <universe_id>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Every output should show `ok`. Flag anything pending, missing, or without a recipe.
|
|
26
|
+
|
|
27
|
+
### 3. Decision-code alignment
|
|
28
|
+
|
|
29
|
+
**The most important check.** For every decision in `astra.yaml`, confirm the code accepts it as a parameter and does not hardcode its value. Compare `astra info --decisions` against `grep -r "add_argument" scripts/`.
|
|
30
|
+
|
|
31
|
+
### 4. Results match spec
|
|
32
|
+
|
|
33
|
+
For every output in `astra.yaml`, verify `results/<universe_id>/<output_id>.<ext>` exists and looks well-formed. For `type: metric` outputs, check for valid `{"value": ...}` JSON.
|
|
34
|
+
|
|
35
|
+
## Report
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
| Check | Status |
|
|
39
|
+
|--------------------------|--------|
|
|
40
|
+
| Spec validation | ✓/✗ |
|
|
41
|
+
| Materialization (N/N) | ✓/✗ |
|
|
42
|
+
| Decision-code alignment | ✓/⚠/✗ |
|
|
43
|
+
| Results match spec (N/N) | ✓/✗ |
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
List each finding with file paths and line numbers. If there are failures, suggest concrete fixes.
|
|
47
|
+
|
|
48
|
+
## Rules
|
|
49
|
+
|
|
50
|
+
- **Read-only** — never modify files
|
|
51
|
+
- **One universe at a time**
|
|
52
|
+
- **Never skip check 3** — decision-code alignment is the core value
|
|
53
|
+
- **Always read actual result files** — don't infer from code
|