Skip to main content
Sifr ships two code-quality commands that operate independently of the compiler: sifr fmt for deterministic source formatting and sifr lint for suppressible policy-rule diagnostics. Neither command runs the type-checker or produces binaries, so both are fast to invoke in editors, pre-commit hooks, and CI pipelines.

sifr fmt — format source files

sifr fmt formats .sifr source files using the same parser, AST, and formatter that the Sifr language server uses for editor formatting. The formatter is syntax-aware, deterministic, and idempotent — running it twice produces the same output as running it once.
sifr fmt [OPTIONS] [FILES]...
When no files are supplied, sifr fmt formats the current directory. File and directory inputs discover .sifr files, respect formatter excludes, and honour .gitignore by default.

Common usage

# Format everything in the current directory
sifr fmt .

# Format a single file
sifr fmt src/main.sifr

# Check whether any files would change (exits nonzero if yes)
sifr fmt --check .

# Print a unified diff without writing files
sifr fmt --diff src/main.sifr

# Override line length for a single run
sifr fmt --line-length 100 src/main.sifr

# Format from stdin, write formatted output to stdout
sifr fmt --stdin-filename src/main.sifr < src/main.sifr

Flags

FlagDescription
--checkExit nonzero if any file would change. No files are written.
--diffPrint a unified diff without writing files.
--line-length <N>Override the configured line length for this run.
--stdin-filename <PATH>Format stdin, using PATH for config lookup and diagnostics.
--range <START:END>Format a single file over a UTF-8 byte range. Intended for editor integrations.
--preview / --no-previewEnable or disable preview formatting rules.
--exclude <PATTERN>Add formatter exclude patterns (comma-separated).
--respect-gitignore / --no-respect-gitignoreControl whether VCS ignore files are honoured.
--force-exclude / --no-force-excludeApply or bypass excludes for explicit file targets.
--no-cacheDisable formatter cache reads and writes.
--cache-dir <PATH>Override the formatter cache directory.
--config <KEY=VALUE or PATH>Apply an inline override or an explicit config file.
--isolatedIgnore all discovered sifr.toml files.

Configuration in sifr.toml

Place formatter configuration under the [format] section of sifr.toml.
[format]
line-length = 88
preview = false
docstring-code-format = false
docstring-code-line-length = "dynamic"
exclude = ["target/**"]
respect-gitignore = true
force-exclude = false
cache = true
cache-dir = ".sifr_cache/formatter"
Supported keys:
KeyDescription
line-lengthMaximum line length before the formatter wraps.
previewEnable preview formatting rules.
docstring-code-formatFormat Sifr code snippets inside docstrings.
docstring-code-line-lengthLine length for docstring code blocks ("dynamic" or an integer).
excludePatterns for paths the formatter should skip.
respect-gitignoreHonour .gitignore files when discovering targets.
force-excludeApply exclude patterns even to files named explicitly on the command line.
cacheEnable the formatter result cache.
cache-dirDirectory for formatter cache files.
extendPath or list of paths to additional config files to inherit from.
Ruff-only keys such as target-version and extension are rejected — Sifr formats .sifr source only. Unknown keys fail deterministically so typos surface immediately.

Formatter pragmas

The formatter respects inline pragma comments at Sifr syntax boundaries:
# fmt: off
legacy_matrix = [[1,0,0],[0,1,0],[0,0,1]]
# fmt: on

x = compute()  # fmt: skip
PragmaEffect
# fmt: off / # fmt: onDisable and re-enable formatting for the enclosed region.
# fmt: skipSkip formatting for the statement on this line.
# yapf: disable / # yapf: enableEquivalent to fmt: off / fmt: on.

Style conventions

The formatter canonicalises Sifr’s ownership-qualifier syntax. For example:
# Before formatting
def consume(mut own items: list[int]) -> list[int]:
    return items
# After formatting
def consume(own mut items: list[int]) -> list[int]:
    return items
Editor formatting is LSP-first. Editors should invoke sifr lsp --stdio and request formatting through standard LSP methods — not call sifr fmt directly. See the LSP page for details.

sifr lint — run policy diagnostics

sifr lint runs Sifr-owned policy rules against your source. It operates independently of the compiler — it does not type-check, does not produce binaries, and does not make hard compiler errors suppressible.
sifr lint [OPTIONS] [FILES]...
When no files are provided, sifr lint checks the current directory. Targets may be individual files, directories, or - for stdin.

Common usage

# Lint the current directory
sifr lint

# Lint specific files and directories
sifr lint src demos

# Emit JSON diagnostics
sifr lint --output-format json src/main.sifr

# Show which files would be linted
sifr lint --show-files

# Print a summary of violations by rule
sifr lint --statistics

# Apply all safe fixes automatically
sifr lint --fix src/main.sifr

# Preview what fixes would be applied, without writing
sifr lint --diff src/main.sifr

Flags

FlagDescription
--output-format <FORMAT>concise, full, or json. Controls diagnostic rendering.
--output-file <PATH>Write diagnostic output to a file instead of stdout.
--select <RULE>Run only the specified rules.
--extend-select <RULE>Add rules on top of the configured selection.
--ignore <RULE>Suppress one or more rules.
--fixWrite safe fixes to disk.
--fix-onlyApply fixes without printing remaining diagnostics.
--diffPrint the fix patch without modifying files.
--show-fixesPrint the count of available fixes by rule.
--fixable <RULE>Limit --fix to these rules only.
--unfixable <RULE>Exclude these rules from --fix.
--unsafe-fixesEnable explicitly unsafe policy fixes.
--no-unsafe-fixesDisable unsafe fixes (the default).
--exit-zeroAlways exit 0, even when diagnostics are emitted.
--exit-non-zero-on-fixExit 1 when fixes were applied.
--statisticsPrint a violation count per rule.
--show-filesPrint files that would be linted.
--show-settingsPrint the resolved lint configuration.
--ignore-suppressionsIgnore inline # sifr: ignore[...] comments for this run.
--exclude <PATTERN>Add path exclude patterns.
--extend-exclude <PATTERN>Add patterns on top of configured excludes.
--stdin-filename <PATH>Use PATH for config lookup when reading from stdin.
--config <KEY=VALUE or PATH>Apply an inline override or explicit config file.
--isolatedIgnore all discovered sifr.toml files.

Available rules

Rule IDDefault severityDescription
trailing-whitespacewarningLine ends with one or more whitespace characters.
todo-commentwarningA TODO or FIXME comment is present in the source.
boolean-positional-argumentwarningA bool value is passed positionally where it is ambiguous.
large-parameter-listwarningA function has more parameters than the configured threshold.
duplicate-importwarningThe same name is imported more than once.
These are Sifr-owned rule IDs. Python rule IDs, Ruff prefixes, and # noqa comments have no effect in sifr lint.

Configuration in sifr.toml

Place lint configuration under the [lint] section of sifr.toml.
[lint]
select = ["trailing-whitespace", "todo-comment"]
ignore = ["todo-comment"]
exclude = ["target/**"]
extend-exclude = ["vendor/**"]
include = ["*.sifr"]
respect-gitignore = true
unsafe-fixes = "disabled"

[lint.rules]
large-parameter-list = "warn"
duplicate-import = "ignore"

[lint.per-file-ignores]
"demos/**" = ["todo-comment"]

Suppressing a diagnostic inline

Suppress a policy diagnostic on a specific line with a # sifr: ignore[rule-id] comment:
value = legacy_call()  # sifr: ignore[todo-comment]
Blanket suppressions (without a rule ID) are rejected. Unknown rule IDs in suppression comments are themselves reported as policy diagnostics. Use --ignore-suppressions to run lint as if no inline comments were present.

Fixing violations automatically

sifr lint --fix writes all available safe fixes to disk. Use --diff first to preview what would change:
# Preview fixes
sifr lint --diff src/

# Apply safe fixes
sifr lint --fix src/

# Apply fixes for a specific rule only
sifr lint --fix --fixable trailing-whitespace src/

# Apply fixes and report any that remain unfixed
sifr lint --fix --show-fixes src/
Hard compiler diagnostics are never auto-fixed. Only suppressible policy rules are eligible.

Exit codes

CodeCondition
0No diagnostics emitted, or --exit-zero was used.
1Policy diagnostics remain, or --exit-non-zero-on-fix was used and fixes were applied.
2Usage or configuration error.