lintlang init --github --path AGENTS.mdRun this from your repository root to create
.github/workflows/lintlang.yml. Review the generated file before committing it.
The initializer writes configuration; it does not run a scan, commit a change,
enable Code Scanning, or upload a report itself.
Use an installed LintLang CLI with Python 3.10+, an existing Git repository, and
an instruction file or supported directory that is committed in that repository.
The initializer also works from a subdirectory: it finds the nearest .git
directory or worktree marker. Explicit --path values are interpreted from that
repository root, unlike ordinary scan paths, which are relative to the shell's
invocation directory.
GitHub Actions must be enabled for CI. Code Scanning upload additionally requires an eligible repository with that feature enabled: public repositories on GitHub.com, or eligible organization-owned private/internal repositories with GitHub Code Security. See GitHub's SARIF upload prerequisites. Scanning and preserving a SARIF artifact do not themselves require a successful Code Scanning ingestion.
Choose the actual input your agent reads:
lintlang init --github --path AGENTS.md
lintlang scan AGENTS.md --fail-on fail
git status --shortOpen the generated YAML and review its input path, triggers, pins, failure
threshold, and upload permissions. A new workflow is untracked and will not
appear in an ordinary git diff until staged; use git status and inspect the
file directly. For subsequent tracked changes, use
git diff -- .github/workflows/lintlang.yml.
The generated workflow runs on pull requests and pushes to main. Change that
branch deliberately if your default branch differs. It uses immutable Action
commits, a read-only scan job, SARIF artifact preservation, and a separate upload
job. The current template pins the released LintLang v0.7.0 Action by its full
commit SHA. The Action runs the scanner from that release. Existing generated
workflows require review before replacing their older pin.
The complete maintained example is examples/github-code-scanning.yml. Use that example and the generated file rather than copying competing full workflows from several guides. Inspect the authoritative Action inputs when adapting a step.
Without --path, the initializer chooses the first existing candidate in this
order: AGENTS.md, CLAUDE.md, .github/copilot-instructions.md,
.github/instructions, GEMINI.md, agent.yaml, agent.yml, agent.json.
It selects one target; it does not combine all detected instruction surfaces.
Use --path when more than one candidate exists or when your repository uses a
different layout. The target must resolve to an existing file or directory
inside the repository. A missing target, an outside path, or no automatic
candidate causes a nonzero exit and no generated workflow. This existence check
does not establish that the target contains recognized instruction structures.
The Action's path input is one literal path, not a shell-expanded list. Use an
appropriate directory or separate scan steps for several independent targets.
Re-running with the same generated content prints Up to date and returns 0
without changing it. A different existing .github/workflows/lintlang.yml is
left alone and causes a nonzero exit. Review or merge your customizations before
replacing it with --force:
lintlang init --github --path AGENTS.md --force--force replaces that workflow's content; it does not merge custom jobs or
preserve edits. Other workflow files are not changed. Keep the old version in Git
so a deliberate replacement remains reviewable.
| Invocation | Findings that make the command fail |
|---|---|
CLI without --fail-on |
None by verdict; findings are advisory |
CLI --fail-on fail |
HIGH or CRITICAL |
CLI --fail-on review |
MEDIUM, HIGH, or CRITICAL |
First-party Action with omitted fail-on |
HIGH or CRITICAL; its default is fail |
The Action always supplies its fail-on input to the CLI. For an advisory CI
scan, run the CLI without a verdict threshold rather than inventing an Action
value such as none. The legacy CLI --fail-under quality gate is separate;
see exit behavior.
Missing, unreadable, malformed, or otherwise uninspectable requested inputs stay
on the fatal ERROR channel, regardless of the verdict threshold. Another valid
input cannot mask such an error. Invalid command arguments are also nonzero.
A file that was read and holds nothing LintLang inspects (a package.json, a
JSON Schema, Python with no prompt) is SKIPPED with its reason, never PASS,
and does not change the exit status on its own. A scan in which every file was
SKIPPED, and a named file whose tool-like objects could not be inspected, are
input errors like the zero-file case below; --allow-uninspected is the opt-out.
A scan that inspects zero files — an existing directory with no eligible files,
or --discover finding nothing recognized, with no other matching input — is
an input/coverage error: it exits 1, with a matching ERROR result on every
output channel (terminal, JSON, SARIF). The Action runs the same CLI over its
path input and inherits that exit 1; it has no input that forwards extra CLI
arguments, so the CLI's --allow-empty opt-out is not reachable through the
Action today. In a workflow, point path at a file or directory that is
expected to contain eligible files, or call the CLI directly in a run: step
when the input may legitimately be empty. Prefer an explicit known file when
eligible-file presence matters.
--write-baseline keeps its own stricter, pre-existing behavior here: zero
scanned files is always an error and no baseline is written, --allow-empty
or not.
Create and review a baseline locally, then commit it and add
baseline: .lintlang-baseline.json to the Action's with inputs. Choose fail
or review for remaining findings. CI reads the baseline; it does not create or
refresh one. Follow baseline adoption and lifecycle for exact
matching, path roots, and review of backlog changes.
To generate a report locally, run from the repository root and use a destination different from the input and any baseline:
lintlang scan AGENTS.md --format sarif --fail-on fail > lintlang.sarifSARIF is written to standard output; diagnostics and verdict-gate messages go to standard error. A finding that trips the gate still leaves a report for review. The report uses SARIF 2.1.0. Locations are repository-relative, URI-encoded paths; inputs outside the reporting root are rejected rather than leaking absolute paths. See the SARIF reference for exact payload and location limits.
The Action's optional sarif-file input generates a report but does not upload
it. It writes through a temporary file outside the scanned tree, preserves the
scanner's exit status, and rejects destinations that resolve to the input or
baseline, including symlink aliases. Output-write errors remain fatal.
The canonical workflow separates two jobs:
- Scan and preserve:
contents: read, checkout withpersist-credentials: false, the pinned LintLang Action, then artifact upload underif: always(). The scan job still fails when the gate fails; artifact preservation is notcontinue-on-errorfor the scanner. - Upload: waits for the scan job, downloads its artifact, and ingests SARIF
using
github/codeql-action/upload-sarif. This job hasactions: read,contents: read, andsecurity-events: write. Its fresh source checkout lets GitHub calculate fingerprints during ingestion; LintLang does not emit custom fingerprints or source snippets.
The upload job runs after a scan failure when its event condition permits it.
It skips fork pull requests and Dependabot pull requests; their scans and artifact
preservation still run. Do not work around those restrictions by executing
untrusted pull-request code under pull_request_target or broad write tokens.
Keep write permission out of the scan job.
A generated SARIF file is not proof of successful GitHub ingestion. Verify both the workflow's scan outcome and the upload job, then inspect the repository's Code Scanning results. LintLang findings are code-quality findings, not security severity scores or a security certification.
Initializer refuses an existing file: review the tracked workflow and merge
changes manually, or intentionally use --force. It is protection against silent
replacement, not a failed scan.
No automatic input or no eligible files: choose an existing --path, confirm
that it is committed, and review directory exclusions and extraction coverage.
An unsupported vendor-specific structure can produce no covered findings; a
clean verdict is not proof that every structure was extracted.
A gate fails: distinguish ERROR from findings. Reproduce the same path,
version, filters, baseline, and threshold locally. Do not refresh a baseline or
add continue-on-error simply to turn the job green.
Artifact missing: inspect the scan and artifact-preservation steps first.
Installation failures may prevent report creation; the workflow deliberately
uses if-no-files-found: error. Check that producer and consumer use the same
artifact name and report path.
Upload denied or unavailable: check the event restriction, repository feature eligibility, and upload-job permissions. A skipped fork upload is expected. When only scanning/artifacts are desired, remove the separate upload job rather than granting broader permissions or representing an absent upload as success.
To remove the generated integration, remove .github/workflows/lintlang.yml in a
reviewed change, or remove only its LintLang jobs from a workflow you have since
combined with other checks. Update any required-check configuration that referred
to those jobs. Leave unrelated workflows and repository instructions intact.
Related: integrations, baselines, technical reference, README.