Fast Lanes¶
A fast lane is a named slice of a provider's work with its own CLI subcommand.
While repolish apply -p <alias> already scopes a run to one provider, it still
builds the full session: every mapping the provider declares is staged and
rendered. A lane run stops earlier. It loads exactly one provider and stages
only the templates the lane declares. For a day-to-day edit loop over a handful
of generated files, that is the difference between a quick gate and a short
coffee break.
That shorter loop is only half the story. Fast lanes also let a provider ship
its own focused project utilities without forcing the team to build and maintain
another CLI. If a React provider already owns the templates and conventions for
components, hooks, or route modules, the same provider can expose commands like
react-provider-cli component or react-provider-cli route and generate those
files directly. The team gets scaffolding, standards, and repo-health automation
from one package instead of spreading the same logic across repolish templates,
ad hoc scripts, and a second command-line tool.
Lanes are a quick-development tool. The full system remains the source of truth:
run repolish apply (or the provider's all subcommand) before committing, and
CI should keep checking the full tree.
This section is split into focused pages:
- CLI covers
provider_cli, wiring, config, and trying a lane. - Commands covers provider-owned command declarations.
- Workflows covers how commands and lanes work together.
- Runtime Semantics covers execution rules and advanced cases.
Why they matter¶
- They give a provider an ergonomic developer-facing CLI "for free" once the provider already exists.
- They keep scaffolding logic next to the templates and standards it depends on, instead of duplicating that logic in a second tool.
- They let teams skip expensive full-provider runs when they only need a narrow
update, especially when
post_processwork is the dominant cost. - They still preserve a path back to the full system: the same provider can
offer quick lane commands for local work and a complete
repolish applypass for repo-wide consistency.
In practice that means a provider can serve two roles at once:
- repo maintenance through full repolish runs, and
- day-to-day developer workflows through small, provider-owned commands.
If you are already paying the cost to define provider templates and standards, lanes let you reuse that investment instead of rebuilding it in a separate scaffolding tool.
Declaring lanes¶
Implement create_fast_lanes on the provider. It returns
{lane_name: FastLaneSpec} (or a factory returning one, see
Lane factories), where each spec holds the
same shapes the regular hooks return:
from repolish import FastLaneSpec, Provider, TemplateMapping
class ActionsProvider(Provider[Ctx, BaseInputs]):
def create_file_mappings(self, context):
# context-fed work that needs the full pipeline (peers may feed it)
return {'.github/workflows/ci.yml': 'ci.yml.jinja'}
def create_fast_lanes(self, repolish):
# the repolish namespace only: repo info plus this provider's
# name and version, identical in a lane run and a full apply
header = f'generated by {repolish.provider.alias}'
return {
'actions': FastLaneSpec(
file_mappings={
f'{f.stem}/action.yaml': TemplateMapping(
'_repolish.action.yaml.jinja',
extra_context={
'module': f'{f.stem}.main',
'header': header,
},
)
for f in ACTIONS_SRC.glob('*.py')
},
),
'docs': FastLaneSpec(
file_insertions={
'README.md': {'usage': _usage_block},
'docs/usage.md': {'usage': _usage_block},
},
),
}
The hook receives the repolish namespace and nothing else on purpose. Those
values (repo info, year, this provider's alias and version) are the same whether
the lane runs alone or merged into a full apply, so a lane's file set is stable
either way; this is the namespace every provider gets for free, the one a lane
needs for things like generated file headers. The provider context is
deliberately absent: it may carry peer-provider input that is only complete in a
full run, and a lane declaration that depended on it would produce a different
file set in each mode. A dest whose content genuinely needs data from another
provider belongs in the regular hooks, not in a lane.
One rule follows from the same reasoning: lane templates must live off
TemplateMapping.extra_context. Rendering still flattens the provider's
finalized context into the template namespace, so a lane template that reads a
peer-derived variable renders differently in a lane run than in a full apply.
Keep lane templates self-contained and the parity guarantee holds: a lane run
writes the same bytes a full apply would write for those files.