ahay/src/writing-rsf-flows
Claude Code and agent skill by ahay/src
- community
Checking that the SKILL.md file is still in the repository.
Use when writing or modifying an SConstruct file that drives a Madagascar data-processing flow (Flow/Plot/Result/Fetch/Command).
Install
npx vskill@latest install ahay/src/writing-rsf-flowsSKILL.md
When to use
Use this skill whenever you are authoring or editing an SConstruct file that drives a Madagascar geophysical data-processing pipeline. This covers creating new processing workflows, adding stages to existing flows, configuring plots or results, fetching remote datasets, and integrating non-Madagascar steps via Command/Action. Any SConstruct that starts with from rsf.proj import * is using this DSL.
For a worked end-to-end example of a specific geophysical workflow (NMO, migration, well-tie, etc.), start with the finding-workflow-examples skill.
The DSL surface
framework/rsf/proj.py exposes six top-level functions that wrap a singleton Project object (a subclass of SCons Environment). These are the only functions you should call directly in a user-facing SConstruct.
| Function | One-line description | |
|---|---|---|
Flow(target, source, flow, **kw) | Run a Madagascar command pipeline to produce one or more .rsf files. | |
Plot(target, source, flow=None, **kw) | Run a vplot command to produce a .vpl file (not a deliverable). | |
Result(target, source, flow=None, **kw) | Same as Plot, but copies the output into Fig/ and registers it as a deliverable viewable with scons view. | |
Fetch(file, dir, private=0, **kw) | Download a data file from a remote server into the current directory. | |
End(**kw) | Finalize the build: wire up view, print, lock, and test aliases. Must be called at the end of every SConstruct. | |
Command(targets, sources, action) | SCons built-in re-exported; use for steps that are not Madagascar sf* programs. |
Full module-level signatures from proj.py:
Project.Flow (the underlying method) has this full signature:
Project.Fetch full signature:
Flow in depth
Flow(target, source, flow) is the workhorse of the DSL.
Targets and sources map to `.rsf` files. If target is the string 'spike', the output file is spike.rsf. If source is 'spike', the input is spike.rsf. The .rsf suffix is appended automatically (controlled by the suffix and src_suffix keyword arguments, both defaulting to '.rsf').
The `sf` prefix is implicit inside a `flow` string. When rsfflow=1 (the default), the build system prepends sf to each command token that is recognized as a Madagascar program. So you write 'spike n1=1000' not 'sfspike n1=1000'. This means you should never write the sf prefix inside a Flow command string.
Pipes. Multiple stages are separated with | inside the flow string, just like shell pipes:
Ampersand-separated commands. && inside a Flow command string separates two sequential pipeline groups. Each group is assembled independently (with sf prefixes added, inputs/outputs wired) but they run in the same shell action in sequence, sharing the target output. Use it when you need two related commands that both contribute to producing the target — but if they're independent, prefer two separate Flow calls.
Multi-target flows. Pass a Python list as target to produce several output files from a single command. Use bare names (without .rsf) — the DSL appends the suffix automatically:
Note: names that already contain a . (e.g. 'cmpt.rsf') also work — the DSL skips suffix-adding when a . is already present — but bare names are the idiomatic form.
Zero-input flows (`source=None`). Pass None (not an empty string) when a command generates data with no RSF input:
Internally, when source is falsy the DSL sets stdin=0, meaning no RSF file is piped to stdin.
Multiple sources. Pass a space-separated string or a list. Inside the flow string, refer to extra sources as ${SOURCES[1]}, ${SOURCES[2]}, etc.:
Plot vs. Result
Plot and Result share the same signature:
Two-argument shorthand. When called with two positional arguments, the second is treated as flow and source is set to target:
Plot produces <target>.vpl in the current directory. It is an intermediate artifact — not tracked as a deliverable.
Result is identical to Plot but additionally:
- Copies the
.vplfile intoFig/<target>.vpl. - Registers the target for
scons view(opens all results withsfpen). - Registers the target for
scons printandscons lock. - Records the target name in
project.restfor the.rsfprojmanifest.
Rule of thumb: use Plot for intermediate composites or overlays; use Result for the final figure you want to present.
Overlay example (combining two plots):
The second argument 'cmp time' lists source .vpl files; 'Overlay' is a built-in combine mode (see the combine dict in proj.py).
Fetch
Fetch downloads one or more files from a remote server. With the default usedatapath=True, the file is stored under $DATAPATH and a symlink is placed in the current directory (matching RSF's header-and-binary split). Key keyword arguments:
server— URL of the server (default:https://ahay.orgviaget_dataserver()).top— top-level path component on the server (default:'data').private— dict withlogin/password/serverfor FTP-authenticated downloads.usedatapath— ifTrue(default), stores the binary inDATAPATHand symlinks.
Worked example from book/rsf/tutorials/nmo/SConstruct:
This downloads: https://raw.githubusercontent.com/seg/tutorials-2017/master/1702_Step_by_step_NMO/data/synthetic_cmp.npz
After Fetch, the file is available as a source to subsequent Flow or Command calls.
Command and Action
Command (re-exported from SCons) is for steps that are not sf* Madagascar programs — calling a Python function inline, running a third-party tool, or converting between file formats.
Python function as an action:
The function signature (target, source, env) is required by SCons. target and source are lists of SCons Node objects; convert with str(source[0]).
Shell command with a non-Madagascar tool:
Use $SOURCE / $TARGET (SCons variables) for single-file targets inside a Command action string.
Do NOT use Command as a replacement for Flow when the command is an sf* program — use Flow so the DSL handles path resolution, binary file cleanup, and parallel execution correctly.
Parameter interpolation
SConstruct files are plain Python, so you can compute parameters at build-configuration time and interpolate them into flow strings.
`%` formatting (most common in existing Madagascar code):
`.format()`:
f-strings (Python 3.6+):
Note: f-strings work fine in modern Madagascar (Python 3). The historic caution was that SCons uses $VAR substitution in command strings, so a literal $ inside a flow string could clash. Because Madagascar flow strings are processed by rsf.flow.Flow before being handed to SCons, this is not usually a problem — but avoid $ characters in f-string expressions just to be safe.
Multiple parameters:
Running a flow
| Command | Effect | |
|---|---|---|
scons | Build all default targets (everything registered with Flow, Plot, Result). | |
scons view | Open all Result outputs with sfpen (requires a display). | |
scons -n | Dry run: print the commands that would be executed without running them. | |
scons <target> | Build only <target>.rsf (or <target>.vpl). Example: scons filter. | |
scons print | Print all results to the configured printer via pspen. | |
scons lock | Copy results to the locked figures directory for regression testing. | |
scons -j4 | Parallel build using 4 jobs. |
The scons view alias is only registered if at least one Result call has been made.
How it plugs into the larger build
Each chapter/tutorial lives in its own subdirectory with its own SConstruct. The top-level book/SConstruct and intermediate book/<chapter>/SConstruct files use from rsf.book import * instead of from rsf.proj import *. The Book() helper in framework/rsf/book.py recurses into subdirectories and compiles the LaTeX papers alongside the data flows.
A typical book hierarchy:
When writing data-processing flows (not book structure), always use from rsf.proj import *. Only use from rsf.book import * when you are building a multi-chapter book document. See framework/rsf/book.py for the Book() and Paper() helpers.
Common mistakes
- Forgetting `End()`.
Every SConstruct that uses rsf.proj must call End() at the bottom. Without it, the view, print, lock, and test SCons aliases are never registered, and the .rsfproj manifest is never written.
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/writing-rsf-flows/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/writing-rsf-flows)