ahay/src/authoring-sf-programs-python
Claude Code and agent skill by ahay/src
- community
Checking that the SKILL.md file is still in the repository.
Use when authoring a Madagascar sf* main program in Python (fast prototyping with numpy).
Install
npx vskill@latest install ahay/src/authoring-sf-programs-pythonSKILL.md
When to use
Load this skill when writing a new sf<name> program in Python. Python is the fastest iteration path: no compilation step, numpy-native array operations, and easy debugging. New Python programs go in user/<youruser>/M<name>.py.
This skill covers the Python-specific layer only. Always also load:
../authoring-sf-programs/SKILL.md— file naming conventions, self-documentation requirements, parameter style, and build integration shared by every language.
Use this skill instead of the C skill whenever:
- You are prototyping an algorithm and want fast iteration.
- Your operation is naturally expressed as numpy array math.
- You do not need raw C performance (inner loops in pure Python can be 10–100x slower than C; use numpy vectorization to avoid that).
Skeleton
This skeleton has been smoke-tested against a real sfspike-generated RSF file and runs correctly. The key difference from the plan's template: the correct import is rsf.api as rsf (the installed module name), not import m8r, and rsf.Output() takes only a tag argument — shape is inherited automatically from the first input opened.
Bulk-read variant (whole array at once)
When the algorithm needs the full dataset in memory, read everything at once:
Correction from the plan's template
The plan template showed m8r.Output("out", fin). This is wrong in two ways:
- Prefer
import rsf.api as rsfoverimport m8r. Both work (the installedm8r.pyis bit-identical torsf/api.py), but the self-doc scraper's I/O-recognition regex (inpout['python']inframework/rsf/doc.py) is anchored torsf.Input/rsf.Outputcalls. Usingimport m8rwould lose the auto-generated< in.rsf > out.rsfsynopsis insfdocoutput. Note thatapi/python/test/clip.pyandapi/python/test/afdm.pyboth useimport m8r— they still work, but their sfdoc entries are less informative. rsf.Output(tag='out', data_format=None)accepts only a tag and an optional format string — there is no second positional argument for a source file. Shape inheritance is automatic: when writing begins, the internal_RSF.fileflush()copies header parameters from the first opened input.
Self-doc format
The scraper in framework/rsf/doc.py uses this regex for Python files (comment['python']):
This matches the first string literal in the file — specifically the first '...' or """...""" that appears before any other quoted string. In practice: put a module-level docstring immediately after the shebang line:
or a triple-quoted version:
The first line of the docstring becomes the program's one-line description shown in sfdoc sfname. Subsequent lines become the comments section.
Real example from api/python/test/afdm.py: that file has no leading docstring, so its sfdoc description is empty. Real example from user/sbader/Menergy.py:
The parameter scraper regex for Python (param['python']) captures par.bool(...), par.int(...), par.float(...), and par.string(...) calls along with optional trailing # [range] description comments:
So a parameter line like:
scrapes as: type=float, name=factor, default=1.0, range=[0,inf], desc="scale factor applied to every sample".
m8r.Input / m8r.Output
Both classes live in api/python/m8r.py (installed as rsf/api.py). They extend _File, which extends File.
rsf.Input(tag='in')
Opens an RSF file for reading.
tag='in'means standard input (the default, used when the program reads from a pipe).- Any other tag string (e.g.,
'vel','ref') opens the file named by the command-line argumentvel=some.rsf.
From afdm.py:
Header reads — extract axis metadata from the RSF header:
Reading data:
fin.close() is optional — the destructor closes automatically.
rsf.Output(tag='out', data_format=None)
Opens an RSF file for writing.
tag='out'means standard output (the default).- Shape and format are inherited automatically from the first
rsf.Input()opened in the same program; you do not pass a source file. - Use
.put()to override or add header values before any.write()call.
Writing metadata:
Writing data:
The write() method calls np.reshape(data.astype(np.float32), (data.size,)) before writing, so the shape of the array passed does not need to match the file shape exactly — the total element count must match.
Closing:
m8r.Par
rsf.Par(argv=sys.argv) parses command-line arguments of the form key=value. A default instance is created automatically on module import; call rsf.Par() explicitly in your program to initialize it properly.
Scalar parameters
Booleans on the command line: verb=y or verb=1 → True; verb=n or verb=0 → False.
List (array) parameters
If fewer values are given than requested, the last value is repeated to fill.
Program name
Parameter file
Pass par=somefile.par on the command line to read key=value pairs from a file; they merge with command-line arguments.
Numpy shape conventions
Madagascar numbers axes starting from 1, with axis 1 being the fastest-varying (stored contiguously in memory, analogous to C's inner loop). Numpy uses C order (row-major), where the last index is fastest-varying.
Therefore, when you allocate a numpy array to hold Madagascar data, the axis ordering is reversed:
| Madagascar | Numpy shape | |
|---|---|---|
| n1=100 samples/trace | last dimension: (..., 100) | |
| n2=50 traces | second-to-last: (50, 100) | |
| n3=10 shots | (10, 50, 100) |
Example: a 3D dataset with n1=500, n2=200, n3=10:
Common transpose patterns
When an algorithm expects "time along rows" (C convention: time last), your layout is already correct. When an external library expects "columns are samples" (Fortran convention), transpose:
When writing back, remember to restore the Madagascar axis order:
fin.shape() and axis reversal
The File.shape() method returns a tuple already reversed for numpy:
SConstruct integration
Declaring Python programs
In user/<youruser>/SConstruct, list each Python main program name (without the M prefix and without .py) in the pyprogs variable:
What the build does
When you run scons in the top-level source tree, the build system processes user/<youruser>/SConstruct. For each name in pyprogs, the inline install loop does:
- Copies
M<name>.pydirectly to$RSFROOT/bin/sf<name>(no compilation) viaenv.InstallAs. - Sets the file executable (
chmod 0o755) viaenv.AddPostAction.
There is no shell wrapper generated for Python programs. The Python file itself becomes the installed binary, called directly by the system Python interpreter via the shebang line (#!/usr/bin/env python3). This is different from C programs (which are compiled ELF binaries) but identical in usage from the user's perspective.
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/authoring-sf-programs-python/SKILL.md
Popularity
- Repository stars
- 338
- Repository forks
- 187
- 7-day trend score
- 29
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/ahay/src/authoring-sf-programs-python)