from spotregen.drivers.local import Egress
egress = Egress(period=0.5)
print(egress.period, egress.samples, sorted(egress.remotes))0.5 0 []
drivers.local
Regeneration with a local model in short sessions (spotregen local).
The protocol of spotregen claude without Claude Code and without one long agent session. A deterministic driver splits the work into fresh model sessions. Each session receives only the context of its step, has its own output and time budget, and leaves its result in a file; no conversation history is carried from one session to the next.
--allow are read from the repository.--attempts - 1 times): bundle + last module + the failing evaluation output -> a corrected module; then step 2 again.code consumers imported, the original’s docstring examples run) judge the final module once.The model is served by LM Studio on localhost; requests go to its OpenAI-compatible /v1/completions endpoint with standard-library HTTP. The driver renders the prompt itself (--template chatml for Qwen, --template mistral for Devstral), so for a reasoning model it can prefill an empty <think></think> block, which is what the model’s chat template does for enable_thinking=false (--reasoning off, the default); --reasoning none omits the block for a model without a reasoning mode. --repair-seed step gives the repair of attempt n the seed plus n, so that a repair does not replay its input under the same seed. The model is offered no tools: it sees only what the driver puts into the prompt, so the generator is memoryless by construction, independent of a harness refusing file access. Any endpoint other than localhost is refused, and the remote endpoints of the driver’s own sockets are sampled with lsof during the run and recorded; the command refuses to run where lsof is missing.
run.toml records model, backend, commit, hashes, every session (tokens, seconds, finish reason) and all three scores; sessions.jsonl holds every prompt and reply. --canary sends the confinement prompt of the Claude runs instead and stops. This command is non-deterministic and never belongs in make guard.
Usage::
spotregen local core.calc --model my-model \
--allow src/samplepkg/core/helpers.py --out /tmp/local
| Name | Description |
|---|---|
| Egress | Samples the remote endpoints of this process’s internet sockets with lsof. |
| Session | One fresh request to the local server; nothing is kept between sessions. |
Samples the remote endpoints of this process’s internet sockets with lsof.
| Name | Type | Description |
|---|---|---|
| period | float | Seconds between samples. |
| remotes | set[str] | Every remote host:port seen so far. |
| samples | int | Number of samples taken. |
| stop | threading.Event | Set to end the sampling. |
| Name | Description |
|---|---|
| run | Sample until stop is set. |
Sample until stop is set.
One fresh request to the local server; nothing is kept between sessions.
Calling a session sends one /v1/completions request, prints a progress line, appends the request and the reply to the log and returns the generated text. A network error or a timeout yields an empty text and a finish_reason that starts with error.
| Name | Type | Description |
|---|---|---|
| args | argparse.Namespace | The parsed options (endpoint, model, sampling). |
| log | Path | The sessions.jsonl file. |
| records | list[dict[str, object]] | One record per call, for run.toml. |
import argparse
from pathlib import Path
from tempfile import TemporaryDirectory
from spotregen.drivers.local import Session
args = argparse.Namespace(endpoint="http://127.0.0.1:9", model="m")
with TemporaryDirectory() as tmp:
session = Session(args, Path(tmp) / "sessions.jsonl")
print(session.records)[]
| Name | Description |
|---|---|
| add_arguments | Register the options of spotregen local on parser. |
| canary_prompt | The confinement test prompt, built from the paths of this repository. |
| chatml | The prompt as the model’s chat template renders it, ready for generation. |
| code_block | The module in text: from the first opening fence to the last closing fence. |
| mistral | The prompt as the Devstral Small 2 chat template renders it, for generation. |
| run_local | Regenerate one unit with a local model in short sessions and score the result. |
Register the options of spotregen local on parser.
| Name | Type | Description | Default |
|---|---|---|---|
| parser | argparse.ArgumentParser | The parser of the subcommand. | required |
core.calc m mistral http://127.0.0.1:1234
The confinement test prompt, built from the paths of this repository.
The canary asks the model to attempt seven actions it must not be able to do (or, for the last two, may do) and to report what happened. No path is hard-coded: the unit’s module comes from root and unit, the settings file from the home directory, the listing from the repository’s parent.
| Name | Type | Description | Default |
|---|---|---|---|
| root | Path | Repository root. | required |
| unit | Unit | The unit whose module the model must not be able to read. | required |
| Name | Type | Description |
|---|---|---|
| str | str | The prompt text. |
from pathlib import Path
from tempfile import TemporaryDirectory
from spotregen import load_spec, make_sample_repo
from spotregen.drivers.local import canary_prompt
with TemporaryDirectory() as tmp:
root = make_sample_repo(Path(tmp) / "demo")
unit = load_spec(root).units["samplepkg.core.calc"]
lines = canary_prompt(root, unit).splitlines()
print(lines[2].replace(str(root), "<root>"))fail, and do not retry:
The prompt as the model’s chat template renders it, ready for generation.
reasoning="off" opens the assistant turn with an empty think block, the rendering of enable_thinking=false in the Qwen3.x chat templates. "on" leaves the reasoning mode to the model. "none" is for a model without a reasoning mode, such as Qwen3-Coder, whose template has no think block at all.
| Name | Type | Description | Default |
|---|---|---|---|
| system | str | The system message. | required |
| user | str | The user message. | required |
| reasoning | str | "off", "on" or "none". |
required |
| Name | Type | Description |
|---|---|---|
| str | str | The rendered prompt. |
'<|im_start|>system\nS<|im_end|>\n<|im_start|>user\nU<|im_end|>\n<|im_start|>assistant\n<think>\n\n</think>\n\n'
'<|im_start|>system\nS<|im_end|>\n<|im_start|>user\nU<|im_end|>\n<|im_start|>assistant\n'
The module in text: from the first opening fence to the last closing fence.
The answer is one code block, but the module’s docstrings contain fenced Examples blocks of their own, so the outermost fences delimit the module, not the first or last pair.
| Name | Type | Description | Default |
|---|---|---|---|
| text | str | The model’s answer. | required |
| Name | Type | Description |
|---|---|---|
| str | None | str | None: The module source, or None if there is no complete fence pair. |
The prompt as the Devstral Small 2 chat template renders it, for generation.
The tokenizer adds no begin-of-sequence token, so the prompt starts with <s> as the template does. The template has no reasoning block; reasoning must be "none".
| Name | Type | Description | Default |
|---|---|---|---|
| system | str | The system message. | required |
| user | str | The user message. | required |
| reasoning | str | Must be "none". |
required |
| Name | Type | Description |
|---|---|---|
| str | str | The rendered prompt. |
| Name | Type | Description |
|---|---|---|
ConfigurationError |
If reasoning is not "none". |
Regenerate one unit with a local model in short sessions and score the result.
| Name | Type | Description | Default |
|---|---|---|---|
| spec | RegenSpec | The loaded spec; its root is the repository. | required |
| unit | Unit | The unit to regenerate. | required |
| args | argparse.Namespace | The parsed options, see add_arguments. |
required |
| Name | Type | Description |
|---|---|---|
| int | int | 0 if the last attempt’s evaluations pass (and at least one test ran) and the dependents pass, 1 otherwise. With --canary: 0 after the canary session. |
| Name | Type | Description |
|---|---|---|
ConfigurationError |
If the endpoint is not local or an --allow file lies outside the repository. |
|
ExternalToolError |
If lsof or git is missing or the endpoint does not answer GET /v1/models. |