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.
Files changed (46) hide show
  1. lightcone/cli/__init__.py +16 -0
  2. lightcone/cli/claude/lightcone/agents/lc-extractor.md +114 -0
  3. lightcone/cli/claude/lightcone/guides/astra-reference.md +290 -0
  4. lightcone/cli/claude/lightcone/guides/lightcone-cli-reference.md +75 -0
  5. lightcone/cli/claude/lightcone/guides/ui-brand.md +86 -0
  6. lightcone/cli/claude/lightcone/hooks/langfuse_git_commit_hook.py +303 -0
  7. lightcone/cli/claude/lightcone/hooks/langfuse_hook.py +894 -0
  8. lightcone/cli/claude/lightcone/hooks/langfuse_prepare_commit_msg.py +142 -0
  9. lightcone/cli/claude/lightcone/hooks/langfuse_session_init_hook.py +83 -0
  10. lightcone/cli/claude/lightcone/hooks/langfuse_utils.py +457 -0
  11. lightcone/cli/claude/lightcone/scripts/activate-venv.sh +44 -0
  12. lightcone/cli/claude/lightcone/scripts/check-lc-run.sh +140 -0
  13. lightcone/cli/claude/lightcone/scripts/session-start.sh +140 -0
  14. lightcone/cli/claude/lightcone/scripts/validate-on-save.sh +77 -0
  15. lightcone/cli/claude/lightcone/skills/lc-build/SKILL.md +92 -0
  16. lightcone/cli/claude/lightcone/skills/lc-build/assets/loop-prompt.md +92 -0
  17. lightcone/cli/claude/lightcone/skills/lc-build/scripts/setup-lc-build.sh +240 -0
  18. lightcone/cli/claude/lightcone/skills/lc-feedback/SKILL.md +94 -0
  19. lightcone/cli/claude/lightcone/skills/lc-migrate/SKILL.md +98 -0
  20. lightcone/cli/claude/lightcone/skills/lc-new/SKILL.md +183 -0
  21. lightcone/cli/claude/lightcone/skills/lc-verify/SKILL.md +53 -0
  22. lightcone/cli/claude/lightcone/templates/CLAUDE.md +32 -0
  23. lightcone/cli/commands.py +2327 -0
  24. lightcone/cli/plugin.py +34 -0
  25. lightcone/engine/__init__.py +42 -0
  26. lightcone/engine/assets.py +418 -0
  27. lightcone/engine/container.py +370 -0
  28. lightcone/engine/io_manager.py +27 -0
  29. lightcone/engine/runner.py +1017 -0
  30. lightcone/engine/site_registry.py +142 -0
  31. lightcone/engine/status.py +135 -0
  32. lightcone/engine/targets.py +68 -0
  33. lightcone/engine/tree.py +245 -0
  34. lightcone/eval/__init__.py +25 -0
  35. lightcone/eval/build.py +148 -0
  36. lightcone/eval/cli.py +176 -0
  37. lightcone/eval/graders.py +192 -0
  38. lightcone/eval/harness.py +265 -0
  39. lightcone/eval/models.py +117 -0
  40. lightcone/eval/report.py +214 -0
  41. lightcone/eval/sandbox.py +394 -0
  42. lightcone_cli-0.2.0.dist-info/METADATA +16 -0
  43. lightcone_cli-0.2.0.dist-info/RECORD +46 -0
  44. lightcone_cli-0.2.0.dist-info/WHEEL +4 -0
  45. lightcone_cli-0.2.0.dist-info/entry_points.txt +2 -0
  46. 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