Skip to content

Commit 4d5f187

Browse files
khushalkottaruGui-FernandesBR
authored andcommitted
chore: update toolkit files
1 parent ccd52aa commit 4d5f187

2 files changed

Lines changed: 127 additions & 125 deletions

File tree

CLAUDE.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,44 @@ Environment → Motor → Rocket → Flight
6969
- **Test names:** `test_methodname_expectedbehaviour` pattern. Use `pytest.approx` for float comparisons.
7070
- **Tests follow AAA** (Arrange, Act, Assert) with fixtures from `tests/fixtures/`.
7171
- **Backward compatibility:** Use deprecation warnings before removing public API features; document changes in CHANGELOG.
72+
73+
# RocketPy fork instructions for Claude Code
74+
75+
## What this repo is
76+
RocketPy is a 6-DOF rocket trajectory simulator in pure Python. The main source
77+
code lives in `rocketpy/`. Tests live in `tests/`. The default branch is `master`.
78+
79+
## My workflow
80+
- I am a solo contributor. Jules scouts issues and creates a branch. I hand off
81+
to you (Claude Code) to build the implementation.
82+
- Branches follow the pattern `scout/YYYY-MM-DD-brief-description`.
83+
- Read `scout_report.md` in the repo root at the start of every session — it
84+
contains the selected issue and any context Jules gathered.
85+
86+
## Scope rules — read these carefully
87+
- Only touch files directly relevant to the issue. Do not refactor unrelated code.
88+
- Do not modify existing function signatures unless the issue explicitly requires it.
89+
- Do not add type hints — the codebase does not use them.
90+
- Do not rename variables or reformat code outside the files you are changing.
91+
- If you think something adjacent should be fixed, mention it in a comment to me
92+
instead of changing it.
93+
94+
## Code conventions
95+
- Docstrings: NumPy format only. Every new public function and class needs one.
96+
Parameter types go in the docstring (e.g. `x : float`), not as type hints.
97+
Do not document units in the type field — just the type name.
98+
- No magic numbers. Any numeric constant needs a comment explaining what it is.
99+
- Follow the style of the surrounding code exactly — indentation, spacing, naming.
100+
101+
## Before you consider something done
102+
- All new public functions have NumPy docstrings
103+
- Tests written and passing
104+
- No files modified outside the scope of the issue
105+
- No type hints added anywhere
106+
- Diff is clean — no stray whitespace changes, no reformatting of untouched lines
107+
108+
## What to ask me before doing
109+
- Any change to an existing public API
110+
- Adding a new dependency
111+
- Creating a new file that isn't a test or a direct implementation of the issue
112+
- Anything that feels like it goes beyond the issue scopeß

jules_handoff.sh

Lines changed: 86 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
#!/bin/bash
22
# ─────────────────────────────────────────────────────────
3-
# jules-handoff.sh
4-
# Pulls a Jules branch and launches Claude Code with full context
3+
# jules_handoff.sh
4+
# Checks out a Jules scout branch and launches Claude Code with context
55
#
66
# Usage:
7-
# ./jules-handoff.sh # interactive branch picker
8-
# ./jules-handoff.sh <branch-name> # direct branch name
9-
# ./jules-handoff.sh <github-pr-url> # paste a Jules PR URL
7+
# ./jules_handoff.sh # interactive branch picker
8+
# ./jules_handoff.sh <branch-name> # direct branch name
9+
# ─────────────────────────────────────────────────────────
10+
11+
# ── Config — only thing to change when reusing across repos
12+
DEFAULT_BRANCH="master"
13+
UPSTREAM_FALLBACK="https://github.com/RocketPy-Team/RocketPy.git"
1014
# ─────────────────────────────────────────────────────────
1115

1216
set -e
1317

1418
REPO_DIR=$(git rev-parse --show-toplevel 2>/dev/null)
1519
if [ -z "$REPO_DIR" ]; then
16-
echo "❌ Not inside a git repo. Run this from your astropy fork directory."
20+
echo "❌ Not inside a git repo."
1721
exit 1
1822
fi
1923

@@ -23,34 +27,22 @@ cd "$REPO_DIR"
2327

2428
UPSTREAM_URL=$(git remote get-url upstream 2>/dev/null || echo "")
2529
if [ -z "$UPSTREAM_URL" ]; then
26-
echo "❌ No upstream remote found. Run: git remote add upstream <original-repo-url>"
30+
echo "❌ No upstream remote found. Run: git remote add upstream $UPSTREAM_FALLBACK"
2731
exit 1
2832
fi
2933

30-
# Parse owner/repo from URL (handles both https and ssh)
31-
UPSTREAM_REPO=$(echo "$UPSTREAM_URL" | sed 's|https://github.com/||' | sed 's|git@github.com:||' | sed 's|[.]git$||')
34+
UPSTREAM_REPO=$(echo "$UPSTREAM_URL" \
35+
| sed 's|https://github.com/||' \
36+
| sed 's|git@github.com:||' \
37+
| sed 's|[.]git$||')
3238

3339
echo "📡 Upstream: $UPSTREAM_REPO"
3440

35-
# ── Step 1: Determine the Jules branch ───────────────────
41+
# ── Step 1: Determine the branch ─────────────────────────
3642

3743
if [ -n "$1" ]; then
38-
INPUT="$1"
39-
40-
# If it's a GitHub PR URL, extract the branch from the API
41-
if [[ "$INPUT" == https://github.com/* ]]; then
42-
echo "🔍 Fetching branch from PR URL..."
43-
PR_NUMBER=$(echo "$INPUT" | grep -oE '/pull/[0-9]+' | grep -oE '[0-9]+')
44-
REPO_SLUG=$(echo "$INPUT" | sed 's|https://github.com/||' | cut -d'/' -f1-2)
45-
BRANCH=$(curl -s "https://api.github.com/repos/$REPO_SLUG/pulls/$PR_NUMBER" \
46-
| python3 -c "import sys,json; print(json.load(sys.stdin)['head']['ref'])")
47-
echo "📌 Branch: $BRANCH"
48-
else
49-
BRANCH="$INPUT"
50-
fi
51-
44+
BRANCH="$1"
5245
else
53-
# Interactive: list recent Jules branches
5446
echo ""
5547
echo "🔍 Fetching recent branches from origin..."
5648
git fetch origin --quiet
@@ -61,13 +53,13 @@ else
6153

6254
BRANCHES=$(git branch -r --sort=-committerdate \
6355
| grep 'origin/' \
64-
| grep -v 'origin/main' \
56+
| grep -v "origin/$DEFAULT_BRANCH" \
6557
| sed 's|origin/||' \
6658
| head -20)
6759

6860
if [ -z "$BRANCHES" ]; then
69-
echo "No branches found other than main."
70-
echo "Jules may not have created a branch yet — check jules.google.com"
61+
echo "No branches found other than $DEFAULT_BRANCH."
62+
echo "Jules may not have created a branch yet."
7163
exit 1
7264
fi
7365

@@ -89,7 +81,7 @@ else
8981
fi
9082
fi
9183

92-
# ── Step 2: Pull the branch locally ──────────────────────
84+
# ── Step 2: Check out the branch ─────────────────────────
9385

9486
echo ""
9587
echo "📥 Checking out branch: $BRANCH"
@@ -105,167 +97,136 @@ fi
10597

10698
echo "✅ On branch: $BRANCH"
10799

108-
# ── Step 3: Read and extract selected issue from scout_report.md ──
100+
# ── Step 3: Read scout_report.md ─────────────────────────
109101

110102
echo ""
111-
echo "📋 Reading Jules scout report..."
103+
echo "📋 Reading scout report..."
112104

113105
SCOUT_REPORT=""
106+
SELECTED=""
107+
114108
if [ -f "scout_report.md" ]; then
115-
# Read the selected issue number from the SELECTED ISSUE line
116109
SELECTED=$(grep "SELECTED ISSUE:" scout_report.md | grep -oE '[0-9]+' | head -1)
117110

118111
if [ -z "$SELECTED" ]; then
119112
echo ""
120-
echo "👉 Open scout_report.md and fill in the SELECTED ISSUE number (1, 2, or 3)"
121-
echo " Then re-run this script."
113+
echo "👉 Open scout_report.md and fill in the SELECTED ISSUE number, then re-run."
122114
exit 0
123115
fi
124116

125117
echo "✅ Selected issue: #$SELECTED"
126118

127-
# Extract only the selected issue section
128-
SCOUT_REPORT=$(python3 - "$SELECTED" << 'PYEOF'
119+
SCOUT_REPORT=$(python3 << PYEOF
129120
import sys, re
130121
131-
selected = sys.argv[1]
122+
selected = "$SELECTED"
132123
with open("scout_report.md") as f:
133124
text = f.read()
134125
135-
# Find the section matching "## Issue N"
136-
pattern = rf"(## Issue {selected} —.*?)(?=
137-
## Issue \d|$)"
126+
pattern = r"(## Issue " + selected + r" \u2014.*?)(?=## Issue \d|\Z)"
138127
match = re.search(pattern, text, re.DOTALL)
139128
if match:
140129
print(match.group(1).strip())
141130
else:
142-
print(f"Could not find Issue {selected} in scout_report.md")
131+
print(text)
143132
PYEOF
144133
)
145-
echo "✅ Extracted Issue $SELECTED from scout_report.md"
134+
echo "✅ Extracted issue $SELECTED from scout_report.md"
146135
else
147-
echo "⚠️ No scout_report.md found — will use PR description only"
136+
echo "⚠️ No scout_report.md found on this branch"
148137
fi
149138

150-
# ── Step 4: Get PR info and extract issue number ──────────
139+
# ── Step 4: Check for competing PRs ──────────────────────
151140

152-
PR_BODY=""
153-
PR_TITLE=""
154-
ISSUE_NUMBER=""
141+
ISSUE_NUMBER="$SELECTED"
155142
ISSUE_STATUS=""
143+
ISSUE_TITLE=""
156144
ISSUE_BODY=""
157145

158-
if command -v gh &> /dev/null; then
159-
PR_JSON=$(gh pr list --head "$BRANCH" --json body,title,url 2>/dev/null || echo "[]")
160-
PR_TITLE=$(echo "$PR_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d[0]['title'] if d else '')" 2>/dev/null || echo "")
161-
PR_BODY=$(echo "$PR_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d[0]['body'] if d else '')" 2>/dev/null || echo "")
162-
163-
# Try to extract issue number from PR body or branch name
164-
ISSUE_NUMBER=$(echo "$PR_BODY $BRANCH" | grep -oE '#[0-9]+|issues/[0-9]+' | grep -oE '[0-9]+' | head -1)
165-
166-
if [ -n "$ISSUE_NUMBER" ]; then
167-
echo "🔍 Checking upstream issue #$ISSUE_NUMBER..."
168-
ISSUE_JSON=$(gh issue view "$ISSUE_NUMBER" --repo "$UPSTREAM_REPO" --json state,title,body 2>/dev/null || echo "")
169-
170-
if [ -n "$ISSUE_JSON" ]; then
171-
ISSUE_STATUS=$(echo "$ISSUE_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('state','unknown'))")
172-
ISSUE_TITLE=$(echo "$ISSUE_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('title',''))")
173-
ISSUE_BODY=$(echo "$ISSUE_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('body','')[:800])")
174-
echo "📌 Issue #$ISSUE_NUMBER is: $ISSUE_STATUS$ISSUE_TITLE"
175-
176-
if [ "$ISSUE_STATUS" = "closed" ]; then
177-
echo ""
178-
echo "⛔ Issue #$ISSUE_NUMBER is already CLOSED — someone already fixed it."
179-
echo " Aborted. Pick a different Jules branch."
180-
exit 0
181-
fi
146+
if command -v gh &> /dev/null && [ -n "$ISSUE_NUMBER" ]; then
147+
echo "🔍 Checking upstream issue #$ISSUE_NUMBER..."
148+
ISSUE_JSON=$(gh issue view "$ISSUE_NUMBER" --repo "$UPSTREAM_REPO" --json state,title,body 2>/dev/null || echo "")
149+
150+
if [ -n "$ISSUE_JSON" ]; then
151+
ISSUE_STATUS=$(echo "$ISSUE_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('state','unknown'))")
152+
ISSUE_TITLE=$(echo "$ISSUE_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('title',''))")
153+
ISSUE_BODY=$(echo "$ISSUE_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('body','')[:800])")
154+
echo "📌 Issue #$ISSUE_NUMBER: $ISSUE_STATUS$ISSUE_TITLE"
155+
156+
if [ "$ISSUE_STATUS" = "closed" ]; then
157+
echo ""
158+
echo "⛔ Issue #$ISSUE_NUMBER is already closed. Pick a different issue."
159+
exit 0
182160
fi
161+
fi
183162

184-
# Check for competing open PRs
185-
echo "🔍 Checking for competing PRs on issue #$ISSUE_NUMBER..."
186-
COMPETING=$(gh pr list --repo "$UPSTREAM_REPO" --search "fixes #$ISSUE_NUMBER" --json number,title,state,isDraft,url 2>/dev/null || echo "[]")
163+
echo "🔍 Checking for competing PRs..."
164+
COMPETING=$(gh pr list \
165+
--repo "$UPSTREAM_REPO" \
166+
--search "fixes #$ISSUE_NUMBER" \
167+
--json number,title,isDraft,url \
168+
2>/dev/null || echo "[]")
187169

188-
PR_COUNT=$(echo "$COMPETING" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))")
170+
PR_COUNT=$(echo "$COMPETING" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))")
189171

190-
if [ "$PR_COUNT" -gt "0" ]; then
191-
echo ""
192-
echo "⛔ STOP — There is already an open PR for issue #$ISSUE_NUMBER:"
193-
echo "$COMPETING" | python3 -c "
172+
if [ "$PR_COUNT" -gt "0" ]; then
173+
echo ""
174+
echo "⛔ STOP — There is already an open PR for issue #$ISSUE_NUMBER:"
175+
echo "$COMPETING" | python3 -c "
194176
import sys, json
195-
prs = json.load(sys.stdin)
196-
for pr in prs:
177+
for pr in json.load(sys.stdin):
197178
draft = ' [DRAFT]' if pr.get('isDraft') else ''
198179
print(' #' + str(pr['number']) + draft + ': ' + pr['title'])
199180
print(' ' + pr['url'])
200181
"
201-
echo ""
202-
echo " Don't waste your time — pick a different Jules branch."
203-
exit 0
204-
else
205-
echo "✅ No competing PRs found — you're clear to proceed."
206-
fi
182+
echo ""
183+
echo " Pick a different issue."
184+
exit 0
185+
else
186+
echo "✅ No competing PRs — you're clear to proceed."
207187
fi
208188
fi
209189

210-
# ── Step 5: Write Claude Code context file ────────────────
190+
# ── Step 5: Build context file and launch Claude Code ────
211191

212192
CONTEXT_FILE="/tmp/jules-context-$(date +%s).md"
213193

214194
cat > "$CONTEXT_FILE" << CONTEXT
215-
# Jules Handoff Context
195+
# Jules Handoff $UPSTREAM_REPO
216196
217197
## Branch
218198
$BRANCH
219199
220-
## Jules PR Title
221-
${PR_TITLE:-"(not found)"}
200+
## Selected Issue
201+
#${ISSUE_NUMBER:-"unknown"}${ISSUE_TITLE:-"unknown"}
202+
Status: ${ISSUE_STATUS:-"unknown"}
222203
223204
---
224205
225-
## Jules Scout Report (scout.md)
226-
${SCOUT_REPORT:-"(No scout_report.md on this branch — refer to PR description below)"}
206+
## Scout Report
207+
${SCOUT_REPORT:-"(no scout_report.md found)"}
227208
228209
---
229210
230-
## Jules PR Description
231-
${PR_BODY:-"(No PR found — check jules.google.com)"}
211+
## Issue Body
212+
${ISSUE_BODY:-"(could not fetch)"}
232213
233214
---
234215
235-
## Upstream Issue #${ISSUE_NUMBER:-"unknown"}
236-
Status: ${ISSUE_STATUS:-"unknown"}
237-
Title: ${ISSUE_TITLE:-"unknown"}
238-
239-
${ISSUE_BODY:-"(Could not fetch issue body — check https://github.com/astropy/astropy/issues)"}
240-
241-
---
216+
## Instructions for Claude Code
242217
243-
## Your job (Claude Code)
218+
Read CLAUDE.md before doing anything else — it contains scope rules and
219+
conventions you must follow.
244220
245-
The scout report and issue above are your source of truth — ignore any diff noise
246-
from main being ahead of this branch due to the daily sync automation.
247-
248-
1. Read scout.md carefully — Jules has already identified the files and approach.
249-
250-
2. Check if the issue is still open and unassigned upstream before starting:
251-
https://github.com/astropy/astropy/issues/${ISSUE_NUMBER:-""}
252-
253-
3. Run the existing tests for the relevant subpackage first to establish a baseline:
254-
\`python -m pytest astropy/<subpackage>/tests/ -x -v\`
255-
256-
4. Implement the fix described in scout.md. Follow astropy standards:
257-
- Type hints on all new functions
258-
- Numpy-style docstrings
259-
- Tests in the corresponding tests/ directory
260-
- No public API changes unless the issue explicitly requires it
261-
262-
5. Once tests pass, give me a 3-sentence summary of what changed for the PR description.
221+
1. Read the scout report and issue above carefully.
222+
2. Run existing tests for the relevant module first to establish a baseline:
223+
\`python -m pytest tests/ -x -q -k <relevant_test_file>\`
224+
3. Implement the fix. Stay strictly within the scope of the issue.
225+
4. Write tests using pytest.approx for any float assertions.
226+
5. Ensure all new public functions have NumPy docstrings.
227+
6. When done, give me a 3-sentence summary of what changed for the PR description.
263228
CONTEXT
264229

265-
echo "✅ Context ready"
266-
267-
# ── Step 6: Print context and launch Claude Code ──────────
268-
269230
echo ""
270231
echo "🚀 Launching Claude Code..."
271232
echo ""

0 commit comments

Comments
 (0)