Insertion Zones¶
Insertions work in template-rendered files too, but their
repolish:on:tag markers always read as foreign machinery dropped into your
document. Insertion zones solve the cosmetic part: the provider declares a
fillable region whose markers are branded for the content — a badge row, a
footer, a signature — so the rendered file reads as if it was written that way,
while a provider function still fills the body on every apply.
The template ships a default between the markers; anything undeclared (overrides, missing function, render failure) keeps that default instead of failing the file.
Syntax¶
## repolish:insert[badges] start="<!-- generated:badges:on" end="<!-- generated:badges:off -->"
<!-- generated:badges:on my-org/my-repo style=flat -->
_Default badge row for new projects._
<!-- generated:badges:off -->
start/endare literal marker strings;startmatches by prefix, so the opening marker line may carry arguments (<!-- generated:badges:on my-org/my-repo style=flat -->).end-regex="..."replacesendfor generated closers.function="name"(optional) names the provider function to call. Without it, the zone's tag is the function name —repolish:insert[badges]looks upbadges, so the common case needs nothing extra. When several providers register the same function name, qualify with the provider alias —function="my-provider:badges"targets that provider's function specifically, the same naming rule insertion markers use. Because the provider authors the zone into its own template, zones resolve against every function the session's providers contributed — they are not gated by the per-file allowlistcreate_file_insertionsapplies to developer-authored markers.- The zone can repeat in one file; every occurrence is filled. The
|after-renderphase is supported for Jinja-generated zones. - Zones are colon-grammar only — there is no legacy dash spelling. The exact zone and marker syntax is on the Grammar page.
Brand the markers
repolish lint warns (without failing) when literal zone markers lack a
generated / gen / auto word — branded markers are the entire point.
Why custom markers at all¶
Two things set zones apart from plain repolish:on blocks, and both follow from
the same root: a zone is declared by a directive in a provider template, and
that directive is what carries the phase, the default body, and the marker pair.
- The declaration is what opts a region into the
|after-renderphase —repolish:on/repolish:offblocks have no directive to tag, so they cannot run after rendering. - Custom markers only make sense because the provider controls both sides and the markers always live in the document: the provider declares the zone with a directive in the template, writes the marker pair around it, and ships the markers (the directive itself strips during rendering) in the rendered file, guaranteeing they read as content. A reader never has to recognize the block as repolish machinery.
That second point is also the limit:
Do not introduce custom markers in developer-owned files
Directives do not exist in developer-owned files, so a zone cannot be
declared there — hand-writing branded markers in your own file gives
repolish nothing to fill from. And unlike repolish:on / repolish:off,
custom markers carry nothing that says "this is a repolish block": anyone
editing the file would need knowledge of the function and the start/end
markers to make sense of the region. In developer-owned files the opt-in
surface is the function alone — use the standard insertion markers, which
are self-describing.
Developer control¶
You tune what the function sees by editing the arguments on the opening marker
line — say, switching style=flat to style=social. Those edits survive
re-apply: on each run the rendered file re-adopts your opening marker (paired in
occurrence order, like keep blocks) and the body re-fills from your args. The
body itself is always regenerated — never hand-edit inside the markers, same
rule as insertions.
Zones participate in overrides.insertions like ordinary insertion blocks:
disabling a function or tag leaves the template default in place.
Fallbacks¶
The zone body is the provider's promise, but the file must never die over it:
- no function registered → the template default stays, a diagnostic is reported.
- function raises → the template default stays (unlike insertion blocks, which empty the body); diagnostic reported.
- disabled via config → the template default stays; counted as disabled in the insertion report.
Provider side¶
def create_file_insertions(self, context):
def badges(*args):
owner_repo = args[0] if args else 'unknown/unknown'
style = next((a.split('=', 1)[1] for a in args if a.startswith('style=')), 'flat')
return render_badges(owner_repo, style=style)
return {'README.md': {'badges': badges}}
The destination file does not have to appear in this mapping (or in a
list-mode allowlist) for the zone to fill — registering the function anywhere is
enough, since the provider already chose it by declaring the zone. The mapping
only gates developer-authored repolish:on markers.
The function receives the opening marker's arguments the same way an insertion
function receives marker args (shlex-split, --> stripped); the usual signature
forms apply — *args, positional params, or a single InsertionBlock parameter
for full metadata.