You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
extract: reconsider writing anonymous blocks by default #26
mdcode extract README.md writes every block without file= to block-<N>.<ext> in the working directory. On a real README this left more than 20 stray files (block-1.sh, block-4.json, block-198.sql). --ignore-anonymous already prevents this, and the behavior is documented, but it surprises users running a plain extract.
Category: enhancement Summary:extract writes only blocks that have file= unless --update-source is given; remove --ignore-anonymous.
Verification status: Confirmed on main (238c32e). mdcode extract README.md on a README with two untagged blocks (sh, json) wrote block-3.sh and block-4.json beside it. mdcode extract a.md b.md, where each document has one untagged sh block, refused both with ambiguous_target on block-1.sh and wrote nothing. With --ignore-anonymous, both runs wrote only file= targets.
Current behavior: extract writes every selected block that has no file= (an anonymous block) to block-<N>.<ext> in the output directory. --ignore-anonymous skips them. --update-source writes them and adds file=block-<N>.<ext> back into the Markdown, so the block links to the file it produced. Combining --update-source with --ignore-anonymous is invalid_usage. The library mirrors this: the extract() options have ignoreAnonymous (default false) and updateSource, and validate() for the extract operation has ignoreAnonymous. validate --for extract has --ignore-anonymous. The check-sync GitHub Action has an ignore-anonymous input, default true. The README, CLI examples and the shipped Agent Skill pass --ignore-anonymous in nearly every extract example, because a plain extract on a README leaves stray block-<N> files behind.
Desired behavior:
Anonymous blocks are extracted only together with --update-source (library: updateSource: true), because that mode writes their file= back and so leaves no unlinked file. This was decided in triage.
Without --update-source, extract skips anonymous blocks exactly as --ignore-anonymous does today: no file is written, no error is raised, and they don't appear in the result's targets. When a document has no file= blocks, the message is the existing "No code blocks with file metadata found."
With --update-source, behaviour is unchanged: anonymous blocks are written as block-<N>.<ext> and get file= added in the Markdown (or the updated Markdown goes to stdout when reading stdin).
With several documents and --update-source, the all-or-nothing preflight must still include anonymous blocks: two documents that would both write block-1.sh are refused with ambiguous_target before anything is written, as today. The preflight that checks every document before writing must therefore know about --update-source. It must not take the new default and skip anonymous blocks, or the collision would only surface after writes began.
--ignore-anonymous is removed from extract and validate (clean cutover, no alias), so passing it is rejected as an unknown option. The ignoreAnonymous option is removed from the extract and validate library options.
validate --for extract follows the new default: anonymous blocks are not considered.
The check-sync action drops its ignore-anonymous input and stops passing the flag.
Key interfaces:
ExtractOptions: remove ignoreAnonymous. updateSource now also decides whether anonymous blocks are extracted at all.
ValidateOptions (extract operation): remove ignoreAnonymous. Callers that preflight an --update-source run need a way to include anonymous blocks, such as passing updateSource through. The exact shape is the agent's choice; the requirement is the multi-document preflight above.
The CLI extract and validate commands: remove the --ignore-anonymous option. The --update-source / --ignore-anonymous conflict check goes with it.
The JSON envelope's shape is unchanged.
Acceptance criteria:
mdcode extract README.md, on a document with one file= block and two untagged blocks, writes only the file= target, creates no block-* file and exits 0.
mdcode extract --update-source README.md writes block-<N>.<ext> for each anonymous block and adds file=block-<N>.<ext> to it in the Markdown, as before.
mdcode extract a.md b.md, where each document has one untagged sh block, exits 0 and writes nothing. The same run with --update-source exits 1 with ambiguous_target for both documents and writes nothing, in either document.
mdcode extract --ignore-anonymous README.md and mdcode validate --for extract --ignore-anonymous README.md are rejected as unknown options.
Library: extract({ source }) returns no targets for blocks without file=, and ExtractOptions has no ignoreAnonymous property (a type error if passed).
The check-sync action has no ignore-anonymous input, and its tests still pass.
No --ignore-anonymous or ignoreAnonymous remains in the package README, the CLI examples, the Agent Skill (including its "plain extract on a README" common mistake, which no longer applies) or the action docs. The README's "Changes from Earlier Versions" gains an entry: anonymous blocks are no longer extracted by default; drop --ignore-anonymous; pass --update-source to extract them.
A minor bump file describes the breaking change. It should land before the Version Packages PR (🐸 Versioned release #27) merges, so it ships in 0.1.0.
pnpm check passes, and the Intent maintainer check passes with the skill's review recorded.
Out of scope:
The block-<N>.<ext> naming scheme.
dump and run, which keep covering anonymous blocks.
update, which never writes anonymous blocks.
Adding --update-source to validate as a user-facing flag. A run of extract --update-source refuses conflicts itself before writing anything.
Activity
adrianbrowning commentedon Oct 8, 2026
Agent Brief
Category: enhancement
Summary:
extractwrites only blocks that havefile=unless--update-sourceis given; remove--ignore-anonymous.Verification status: Confirmed on main (238c32e).
mdcode extract README.mdon a README with two untagged blocks (sh,json) wroteblock-3.shandblock-4.jsonbeside it.mdcode extract a.md b.md, where each document has one untaggedshblock, refused both withambiguous_targetonblock-1.shand wrote nothing. With--ignore-anonymous, both runs wrote onlyfile=targets.Current behavior:
extractwrites every selected block that has nofile=(an anonymous block) toblock-<N>.<ext>in the output directory.--ignore-anonymousskips them.--update-sourcewrites them and addsfile=block-<N>.<ext>back into the Markdown, so the block links to the file it produced. Combining--update-sourcewith--ignore-anonymousisinvalid_usage. The library mirrors this: theextract()options haveignoreAnonymous(default false) andupdateSource, andvalidate()for the extract operation hasignoreAnonymous.validate --for extracthas--ignore-anonymous. The check-sync GitHub Action has anignore-anonymousinput, default true. The README, CLI examples and the shipped Agent Skill pass--ignore-anonymousin nearly every extract example, because a plainextracton a README leaves strayblock-<N>files behind.Desired behavior:
Anonymous blocks are extracted only together with
--update-source(library:updateSource: true), because that mode writes theirfile=back and so leaves no unlinked file. This was decided in triage.--update-source,extractskips anonymous blocks exactly as--ignore-anonymousdoes today: no file is written, no error is raised, and they don't appear in the result's targets. When a document has nofile=blocks, the message is the existing "No code blocks with file metadata found."--update-source, behaviour is unchanged: anonymous blocks are written asblock-<N>.<ext>and getfile=added in the Markdown (or the updated Markdown goes to stdout when reading stdin).--update-source, the all-or-nothing preflight must still include anonymous blocks: two documents that would both writeblock-1.share refused withambiguous_targetbefore anything is written, as today. The preflight that checks every document before writing must therefore know about--update-source. It must not take the new default and skip anonymous blocks, or the collision would only surface after writes began.--ignore-anonymousis removed fromextractandvalidate(clean cutover, no alias), so passing it is rejected as an unknown option. TheignoreAnonymousoption is removed from the extract and validate library options.validate --for extractfollows the new default: anonymous blocks are not considered.ignore-anonymousinput and stops passing the flag.Key interfaces:
ExtractOptions: removeignoreAnonymous.updateSourcenow also decides whether anonymous blocks are extracted at all.ValidateOptions(extract operation): removeignoreAnonymous. Callers that preflight an--update-sourcerun need a way to include anonymous blocks, such as passingupdateSourcethrough. The exact shape is the agent's choice; the requirement is the multi-document preflight above.extractandvalidatecommands: remove the--ignore-anonymousoption. The--update-source/--ignore-anonymousconflict check goes with it.Acceptance criteria:
mdcode extract README.md, on a document with onefile=block and two untagged blocks, writes only thefile=target, creates noblock-*file and exits 0.mdcode extract --update-source README.mdwritesblock-<N>.<ext>for each anonymous block and addsfile=block-<N>.<ext>to it in the Markdown, as before.mdcode extract a.md b.md, where each document has one untaggedshblock, exits 0 and writes nothing. The same run with--update-sourceexits 1 withambiguous_targetfor both documents and writes nothing, in either document.mdcode extract --ignore-anonymous README.mdandmdcode validate --for extract --ignore-anonymous README.mdare rejected as unknown options.extract({ source })returns no targets for blocks withoutfile=, andExtractOptionshas noignoreAnonymousproperty (a type error if passed).ignore-anonymousinput, and its tests still pass.--ignore-anonymousorignoreAnonymousremains in the package README, the CLI examples, the Agent Skill (including its "plain extract on a README" common mistake, which no longer applies) or the action docs. The README's "Changes from Earlier Versions" gains an entry: anonymous blocks are no longer extracted by default; drop--ignore-anonymous; pass--update-sourceto extract them.pnpm checkpasses, and the Intent maintainer check passes with the skill's review recorded.Out of scope:
block-<N>.<ext>naming scheme.dumpandrun, which keep covering anonymous blocks.update, which never writes anonymous blocks.--update-sourcetovalidateas a user-facing flag. A run ofextract --update-sourcerefuses conflicts itself before writing anything..out-of-scope/extract-shrink-guard.md).feat(extract)!: extract blocks without file= only with --update-source (