# inline Docs — Full Documentation > An autonomous agent that reviews every pull request, guards the merge, and watches your code, CI, cloud, and compliance — all from one portal. --- # Introduction > inline is an autonomous agent that reviews every pull request, guards the merge, and monitors your code, CI, cloud, and compliance — from one portal. # An autonomous reviewer for every pull request **inline reads every pull request your team opens, reviews it the way a senior engineer would, and posts its findings inline on GitHub — automatically, within minutes, at a few cents per PR.** Around that core it adds a merge gate, a feedback loop that learns your team's taste, and a suite of monitors for repository security, CI/CD health, cloud posture, compliance, and autonomous penetration testing. It is one product: an admin portal, a GitHub integration, an always-on background reviewer, and an MCP server for coding agents — powered by Claude, with your data kept in your own cloud tenancy. > **The one-liner:** A code reviewer that never sleeps, never rubber-stamps, and gets quieter and sharper the more your team uses it — plus the security and operational monitors that live in the same PR-shaped workflow. ## What it does When a pull request is opened or updated, inline runs a cost-optimized pipeline: it filters out generated files, diffs only what changed since it last looked, uses a fast model to triage whether the change is substantive, and — only when it is — runs a deep, frontier-model agentic review that can read files, search code, and traverse a code graph before it comments. A validation gate then drops anything low-confidence, below your severity bar, duplicated, or un-anchorable, and posts the rest as a real GitHub review. - **Two-tier by design.** A fast model triages every PR cheaply; the deep model only runs on the ~40–60% that warrant it. Blended cost lands at **a few cents per PR**. - **Quiet on purpose.** A confidence floor, a per-repo severity threshold, cross-commit dedup, and a hard comment cap mean inline comments only when it's confident it's right. "Zero comments" is a successful review. - **It learns.** When your team dismisses, rejects, resolves, or reacts to findings, inline harvests those signals on PR close, proposes suppression rules for patterns you clearly don't want, and distills durable per-repo knowledge into a memory it re-reads on every review. ## More than review The same PR-shaped engine powers a family of monitors, each an optional per-repo or per-org module: | Module | What it does | | --- | --- | | **Merge gate** | A required `inline / review` check that blocks merges while open findings remain — off, report-only, or block by severity. | | **Auto-fix** | Opens a stacked fix-PR that patches a finding and verifies the patch in a sandbox before you see it. | | **Sentinel** | Continuously scans repositories for security issues and raises confirmed alerts. | | **Pentest** | Autonomous red-team agents attack a repo's own code in an isolated sandbox and prove exploitability with non-destructive PoCs. | | **Actions** | Watches CI/CD, triages failures with AI, flags flaky tests, and surfaces GitHub-native security alerts. | | **Cloud** | Monitors your Azure posture, health, and spend with zero stored secrets. | | **Compliance** | Tracks BAA and vendor-agreement coverage across your dependencies and services. | ## Who it's for - **The engineer** who wants a fast, substantive review on every PR without waiting for a human, and inline comments precise enough to act on directly. - **The team lead** who wants a merge gate they can trust, a dashboard of findings and cost, and a reviewer that gets quieter as it learns the team's conventions. - **The security and platform owner** who wants repo scanning, autonomous pentesting, CI/CD health, and cloud posture in one place — all speaking the same finding, severity, and dedup vocabulary. ## Where to next - **[Quickstart →](./quickstart.html)** — connect a repo and get your first review. - **[Core concepts →](./concepts.html)** — repos, reviews, findings, jobs, connections. - **[The review pipeline →](./review-pipeline.html)** — the full path from webhook to posted review. - **[Architecture →](./architecture.html)** — how the portal, background reviewer, and Claude fit together. --- # Quickstart > Connect a repository and get your first automated review — from sign-in to a posted GitHub review in a few minutes. # Quickstart This walks you from zero to inline reviewing your pull requests. You'll sign in, connect GitHub, enable a repository, and open a PR. ## 1. Sign in Open the portal and sign in with your Microsoft work account (Entra ID). The first person from your organization to sign in gets a personal workspace; teams are organized into [organizations](./organizations.html) you can switch between from the top of the sidebar. ## 2. Connect GitHub inline connects to GitHub in one of two ways — see **[Connecting GitHub](./connect-github.html)** for the full comparison: - **GitHub App** (recommended) — installs the `inline` bot into your org. Reviews post under the bot's identity and GitHub delivers events automatically. - **OAuth (Nango)** — connects under your own GitHub account from the portal. inline provisions repo webhooks for you. Go to **Repositories** and follow the connect flow for whichever mode your org uses. ## 3. Enable a repository Connecting makes repos visible; enabling turns on reviews. On the **Repositories** page, toggle a repo **enabled**. That's the only required step — everything below is optional tuning. ## 4. Open a pull request Open or update a PR in the enabled repo. Within a minute or two: 1. inline picks up the change. 2. A fast model triages it; if it's substantive, the deep model reviews it. 3. inline posts a summary comment plus any inline findings, and — if you enabled it — a [walkthrough](./walkthrough.html) link. If inline has nothing worth saying, it says nothing. **Zero comments is a successful review.** ## 5. Interact on the PR You can talk to inline right in the PR by commenting: ```text @inline full review # re-review the whole PR from scratch @inline ask # ask about the change @inline learn # teach it a convention to remember ``` See **[Conversations](./conversations.html)** for the full command set. ## 6. Tune it Once you've seen a few reviews, tune to taste in the portal: - **Severity threshold** and **custom instructions** — [review config](./review-config.html). - **Merge gate** — make `inline / review` a required check ([merge gate](./merge-gate.html)). - **Learnings & skills** — teach conventions and attach expertise ([learnings](./learnings.html)). - **Auto-fix, sandbox tests, walkthroughs** — opt-in [automation](./auto-fix.html). ## Next steps - **[Core concepts →](./concepts.html)** — the vocabulary: repos, reviews, findings, jobs. - **[The review pipeline →](./review-pipeline.html)** — what happens on every PR. - **[Security & monitoring →](./sentinel.html)** — turn on repo scanning, CI/CD, cloud, and pentest. --- # Core concepts > The vocabulary of inline — organizations, connections, repos, reviews, findings, jobs, and the modules built on top. # Core concepts A short tour of the nouns you'll meet everywhere in inline. ## Organization (workspace) The tenancy boundary. Every connection, repo, review, finding, and setting belongs to exactly one organization. Users can belong to several and switch the active one from the sidebar. Everyone gets a personal organization automatically; teams create shared ones and invite [members](./members-invites.html). ## Connection A link to GitHub. It's either the **inline GitHub App** (the bot, org-wide) or an **OAuth** connection under an admin's account. The connection is how inline authenticates every GitHub call — see [Connecting GitHub](./connect-github.html). ## Repository A GitHub repo inline knows about. Connecting makes it visible; **enabling** turns on reviews. A repo inherits workspace defaults but can override most of them — severity threshold, merge gate, custom instructions, path filters, and which modules are on. ## Review One pass over one pull request at one head commit. A review records its triage verdict (`trivial` / `substantive` / `incomplete`), a summary, its findings, and full cost accounting. Reviews are **incremental**: each one covers only what changed since the last one. ## Finding A single issue inline raised: a file, a line range, a severity (`high` / `medium` / `low`), a category (`bug` / `security` / `performance` / `maintainability` / `style`), a confidence score, and a body. A finding is either **posted** to GitHub or **suppressed** with a stored reason — suppressed findings are never discarded, just kept out of the PR. Over its life a finding may become `addressed`, `resolved`, or carry a [feedback outcome](./feedback-loop.html). ## Background work Almost nothing inline does happens while you wait. GitHub events and portal actions kick off work that an always-on background reviewer picks up and runs on its own — reviewing a PR, answering an `@inline` comment, harvesting feedback when a PR closes, recomputing the merge gate, building a walkthrough page, running sandbox tests, generating a fix PR, indexing a code graph, processing a CI/CD run, running a pentest engagement, or sweeping a cloud scan. You see progress live in the portal and results land on the PR. ## Severity & confidence Two dials that govern noise. **Severity** ranks impact (`low` / `medium` / `high`, plus `critical` / `info` in the security modules). **Confidence** is the model's self-assessed certainty in `[0, 1]`. A finding must clear both the repo's severity threshold and the confidence floor to be posted. See [noise control](./review-noise.html). ## The modules The PR reviewer is the core. Around it sit optional, per-org or per-repo modules that share the same finding / severity / dedup vocabulary: - **[Merge gate](./merge-gate.html)** — block merges on open findings. - **[Auto-fix](./auto-fix.html)** — verified fix PRs. - **[Sentinel](./sentinel.html)** — dependency & repo security. - **[Pentest](./pentest.html)** — autonomous red-teaming. - **[Actions](./actions.html)** — CI/CD monitoring. - **[Cloud](./cloud.html)** — Azure posture, health, spend. - **[Compliance](./compliance.html)** — BAA/vendor coverage. ## How it learns Three distinct mechanisms, easily confused: - **[Memory](./repo-memory.html)** — implicit knowledge inline distills about a repo, on its own. - **[Learnings](./learnings.html)** — explicit rules a human teaches (or approves). - **[Skills](./learnings.html#skills)** — authored expertise packs loaded on demand. --- # Architecture > How inline is shaped — a GitHub App, an admin portal, an always-on background reviewer, an MCP server, and Claude, with your data in your own cloud. # Architecture inline is deliberately one deployable thing. There's no separate queue service and no microservice mesh — a single application does the GitHub event handling, the background work, the portal, and the MCP server, powered by Claude and backed by your own cloud tenancy. ## The pieces ```text ┌──────────────────────────────────────────┐ GitHub ──events──► │ inline │ Portal ──HTTP────► │ │ Coding ──MCP─────► │ • GitHub App (events + bot identity) │ agents │ • admin portal │ │ • always-on background reviewer │ │ • MCP server (pre-PR review) │ └──────────┬─────────────────┬─────────────┘ │ │ your cloud database Claude + artifact storage (fast / balanced / deep tiers) │ isolated sandboxes (code-graph, tests, fixes) ``` ## How the work flows The split that makes inline cheap and reliable: **receiving an event does almost nothing, and the background reviewer does the work.** - **Events arrive and are recorded.** When GitHub sends a pull-request event (or you act in the portal), inline verifies it and records the work to be done. This returns immediately — no model work happens on the request path. - **The background reviewer runs continuously.** An always-on worker picks up recorded work, claims each item, serializes work per-PR so two reviews of the same PR never collide, and runs the right task — a review, an `@inline` command, a feedback harvest, a merge-gate recompute, a sandbox test, a fix, an index build, a CI run, or a pentest. Results post back to GitHub and stream live to the portal. ## The model tiers inline uses Claude across three tiers, chosen per task by cost and difficulty — this tiering is the core cost lever: | Tier | Used for | | --- | --- | | **Fast** | Triage, code explorers, repo memory, walkthroughs, first-pass assessment. | | **Balanced** | Chat, deep security and compliance assessment, cloud analysis, CI triage. | | **Deep** | PR deep review, test authoring, fix generation, pentest validation. | Every call's cost is recorded from live token usage, so you always know what a review cost. See [cost & two-tier models](./review-cost.html). ## State & storage - **Your database** holds everything relational — organizations, connections, repos, reviews, findings, and settings. It lives in your own cloud tenancy. - **Artifact storage** holds large objects — code-graph indexes, sandbox videos and screenshots, compliance documents. - **Isolated sandboxes** are ephemeral environments for anything that needs to run code: code-graph builds, [sandbox tests](./sandbox.html), and [fix](./auto-fix.html) verification. ## Live updates The portal gets real-time progress over a live event stream, scoped per organization. Index builds, security fixes, compliance analysis, and cloud scans all stream their phase transitions to the UI. ## Integrations - **GitHub** — via a multi-tenant GitHub App or per-admin OAuth ([connect](./connect-github.html)). - **Microsoft Teams** — Adaptive Card alerts via Power Automate webhooks ([notifications](./notifications.html)). - **MCP** — an authenticated Model Context Protocol server for [pre-PR review](./mcp.html) inside coding agents. - **Web search** — optional search/fetch for reviews, threat news, and compliance research. Read on: **[the review pipeline](./review-pipeline.html)** for what happens on every PR, and **[security & trust](./security-trust.html)** for how your code and credentials are handled. --- # The review pipeline > The full path a pull request takes through inline — from a verified webhook to a posted GitHub review — stage by stage. # The review pipeline Every review is one trip through the same pipeline. A webhook enqueues a job; the worker claims it; the pipeline loads the PR, decides how much to spend, runs the review, filters the output, and posts. This page walks the whole path in order. ## The shape of it ```text GitHub PR opened / updated │ signed webhook (verified) ▼ inline webhook endpoint ──► review job queued │ picked up by the worker ▼ ┌─ the review pipeline ──────────────────────────────────────┐ │ 1. guard / skip checks (repo enabled? PR open? head fresh?) │ │ 2. incremental base (diff only since last reviewed head) │ │ 3. path filters + diff compression │ │ 4. project-type detection → guideline pack │ │ 5. triage — a fast model (trivial vs substantive) │ │ 6. budget gate │ │ 7. deep review — a frontier model, agentic loop │ │ 8. validation gate (confidence, severity, dedup, anchoring) │ │ 9. post GitHub review: summary + inline comments │ │ 10. persist review + findings + cost, absorb repo memory │ └────────────────────────────────────────────────────────────┘ ``` The webhook path does almost nothing — it verifies the signature and queues a job. GitHub gives webhooks only a few seconds to respond, so all model work happens later in the worker. Reviewable PR actions are **opened**, **synchronize**, **ready for review**, and **reopened**; drafts are skipped; a **closed** PR triggers the [feedback harvest](./feedback-loop.html). ## 1. Guards and skips Before spending anything, the pipeline bails early when there's nothing to do: - **Repo disabled** — no review. - **PR no longer open**, or the **head moved** since the job was queued — skip as stale (a newer push already queued a fresher job). - **Bot authors** (e.g. Dependabot) — skip the review, but still sync the merge gate so a required check never gets stuck. ## 2. Incremental base inline reviews **only what's new**. It finds the last completed review for this PR and uses that review's head as the comparison base, so a third push reviews only the third push's changes — deduped against everything already flagged. Commenting `@inline full review` on the PR forces a full re-review from scratch. A force-push that breaks the compare API falls back to a full diff automatically. ## 3. Path filters and diff compression Two cost levers run here before a single token reaches a model: - **Path filters** drop files that never deserve a review — lockfiles, build output, dependencies, generated code, minified JS, migrations, snapshots, images, fixtures. This is the cheapest lever: filtered files cost nothing. Defaults are combined with per-repo and per-workspace globs you set in [review config](./review-config.html). - **Diff compression** ranks the surviving files by change volume, de-prioritizes enormous files, and clips the diff sent to the model. Anything omitted is noted so the review agent can pull it in later with its file-reading tools. See **[Cost & two-tier models](./review-cost.html)** for the full lever list. ## 4. Project-type detection inline detects whether the PR is TypeScript, React, React Native, C#, and so on, and selects the matching **guideline pack** — a language-specific set of review rules folded into the review. ## 5. Triage — a fast model The first model call is cheap on purpose. A fast model reads the diff and returns a structured verdict: ```json { "verdict": "substantive", "summary": "...", "riskAreas": ["auth", "db"] } ``` - **trivial** — no deep review. inline records the verdict, notes a low-risk line on the walkthrough, syncs the gate, and stops. This is where most of the cost savings come from. - **substantive** — proceed to the deep review. When in doubt, triage chooses substantive. ## 6. The budget gate Between triage and the expensive deep review, inline checks the workspace's monthly budget. At 80% of the cap it fires a one-time alert. Past the cap, if **budget-degrade** is on, it stops at triage and records the review as incomplete — which excludes it from the incremental base, so the PR gets a real review next month instead of being silently skipped. ## 7. Deep review — a frontier model The substantive review is an **agentic loop** on a frontier model. The model doesn't just see a diff — it can act: | Tool | What it does | | --- | --- | | `read_file` | Read any file at the PR head, with path-alias and extension resolution. | | `search_code` | Grep file *contents* at the head commit — sees symbols the PR just added. | | `find_files` / `list_directory` | Locate and browse files at the head. | | `dispatch_explorers` | Fan out cheap subagents to map a large PR breadth-first. | | `graph_*` | Traverse a [code graph](./codegraph.html) — definitions, references, importers, call traces — when an index exists. | | `load_skill` | Pull in a [skill](./learnings.html) whose description matches the PR. | | `web_search` / `web_fetch` | Research external context (when web research is enabled). | | `submit_review` | The required terminal tool that returns the findings. | The loop is bounded by a step ceiling and a per-turn output cap. The **explorer subagents** run on a fast model at a fraction of the deep model's price, carrying the token-heavy breadth work while the frontier model does the judgment. If the loop hits the step ceiling without submitting a review, the review is recorded incomplete and the incremental base is held so nothing is lost. The model is told, emphatically, that **a review with no findings is a success** — never comment on style, formatting, naming, docs, or coverage, and refute your own finding before flagging it. ## 8. The validation gate Everything the model submits passes through a validation gate before anything is posted. Findings are suppressed (never dropped — they're stored with a reason and visible in the portal) when they are low-confidence, below the repo's severity threshold, duplicates, un-anchorable to the diff, or beyond the comment cap. This is the machinery that keeps inline quiet — it has its own page: **[Noise control](./review-noise.html)**. ## 9. Post inline posts a single GitHub review: a summary comment (the walkthrough sticky comment, finalized here) plus inline comments anchored to changed lines. If GitHub rejects the inline anchors, it falls back to a body-only review so the findings still land. ## 10. Persist and learn Finally the pipeline records the review and its findings with full cost accounting, reopens any re-confirmed findings, auto-resolves threads for findings that are now addressed, syncs the merge gate, optionally enqueues a [walkthrough page](./walkthrough.html), [sandbox tests](./sandbox.html), or an [auto-fix PR](./auto-fix.html) — and folds this review's summary and findings into the repo's [memory](./repo-memory.html) with a cheap model call. ## The worker Jobs are drained by an in-process worker. It claims jobs atomically, serializes work per-PR so two jobs on the same PR never double-post, dispatches each job to the right handler by type, and continuously recovers stale jobs. Failed jobs retry with exponential backoff up to a bounded attempt count. --- # Cost & two-tier models > How inline holds the blended cost of a review to a few cents — path filters, incremental diffs, prompt caching, diff compression, and two model tiers. # Cost & two-tier models Cost per PR is inline's primary design constraint. A team opens a lot of pull requests; a naive "send the whole diff to the best model" review costs around **$0.25** each. inline targets **~$0.03–0.07 per PR** blended, and gets there by stacking five levers in order of impact. > **The rule of thumb:** filter what you can for free, diff only what changed, cache what repeats, compress what's left, and spend the expensive model only where judgment is actually required. ## The levers, in order ### 1. Path filters (free) The cheapest token is the one never sent. Before anything else, inline drops files that never deserve a review: ```text lockfiles · build output (dist, build, out, bin, obj) · dependencies (node_modules, vendor) generated code · minified JS · migrations · snapshots images · fonts · PDFs · source maps · data files · fixtures ``` Filtered files cost nothing — no triage, no review. The defaults are combined with per-repo and per-workspace globs you set in [review config](./review-config.html). ### 2. Incremental diffs inline reviews **only what's new since it last looked**. The last completed review's head becomes the comparison base, so the third push to a PR reviews only the third push — deduped against everything already flagged. A PR with ten pushes doesn't pay to re-read the first nine. ### 3. Prompt caching inline uses prompt caching aggressively, with three cache breakpoints: - The **system prompt** (role + guideline pack) is byte-identical per repo and cached at a long TTL, so it survives the gaps between a repo's PRs. - The **first user message** (diff + manifest) is cached. - The **last message rolls forward** each agent step, so accumulating tool-result history stays cached across the loop. Cached reads cost a small fraction of fresh input. Keeping per-PR content *out* of the system prompt is a deliberate discipline — anything that changes per review would bust the cache. ### 4. Diff compression What survives the filters is ranked by change volume, enormous files are de-prioritized, and the diff sent to the model is clipped. Omitted files are noted so the review agent can pull exactly what it needs with its file-reading tools instead of paying for everything up front. ### 5. Two model tiers The biggest structural saving is never running the expensive model when it isn't warranted: | Stage | Model tier | Role | | --- | --- | --- | | Triage | Fast model | Classify trivial vs substantive | | Explorers | Fast model | Breadth-first mapping subagents | | Deep review | Frontier model | Judgment, multi-hop reasoning | | Memory / feedback | Fast model | Distill knowledge, draft rules | A fast model triages **every** PR cheaply; the frontier model only runs on the ~40–60% classified substantive. Within a deep review, the token-heavy breadth work is delegated to fast **explorer subagents** at a fraction of the frontier model's input price, leaving the deep model to do the reasoning. inline is powered by Claude across every tier. ## Cost accounting inline accounts for every review's cost from live token usage, tracking input, output, and cached-read and cached-write tokens separately so cached tokens are never double-billed. Each review stores a per-model breakdown (triage, review, explore) you can inspect in the portal. ## Monthly budgets Every workspace has a monthly budget. inline fires a one-time alert at 80% of the cap. Past the cap, with **budget-degrade** enabled, reviews stop at the cheap triage stage and are marked incomplete — which excludes them from the incremental base, so a PR that got a degraded review this month gets a full one next month rather than being silently skipped. Configure the cap and degrade behavior in [review config](./review-config.html). ## What you can tune In the portal you can adjust, per repo or per workspace: - **Path filters** — additional globs to exclude. - **Reasoning effort** — how hard the deep model thinks (low through max). - **Severity threshold** and **confidence floor** — see [noise control](./review-noise.html). - **Monthly budget** and **budget-degrade** behavior. See [review config](./review-config.html) for the full list. --- # Noise control > The validation gate — confidence floor, severity threshold, dedup fingerprints, line anchoring, and the comment cap — that keeps inline quiet and trusted. # Noise control A reviewer that comments on everything gets muted. inline's trust comes from the opposite instinct: **comment only when confident it's right, and treat zero comments as a successful review.** Everything the model submits passes through a validation gate before a single comment is posted. > Suppressed findings are never dropped. Each is stored with a reason and remains visible in the portal — so you can audit what inline chose *not* to say, and tune the thresholds if it's being too shy or too loud. ## The validation gate The gate runs after the deep review and before posting. A finding is suppressed for any of these reasons: | Reason | Trigger | | --- | --- | | Low confidence | Confidence below the floor (default **0.55**). | | Below threshold | Severity below the repo's threshold (default **medium**). | | Duplicate | Already posted earlier in this PR, or seen twice this review. | | Invalid line | Points at a line not present in the PR diff (after a recovery attempt). | | Comment cap | Beyond the postable-findings cap (default **12**). | ### Confidence floor Every finding carries a model-assigned confidence from 0 to 1. In production tuning, confirmed-real findings clustered around 0.55–0.60 while dismissals clustered at 0.80+, so the floor sits at **0.55**. Below it, a finding is stored but not posted. ### Severity threshold Each repo has a severity threshold (**low** / **medium** / **high**, default medium). Findings below it are suppressed. Set it per-repo or per-workspace in [review config](./review-config.html) — a mature codebase might raise it to high; a security-critical one might drop it to low. ### Dedup fingerprints Each finding gets a stable fingerprint built from the repo, PR, file, a normalized title, and a coarse line bucket: - The **normalized title** is lowercased and stripped to its first several words — so trivial rewordings collapse to the same identity. - The **line bucket** is coarse — so small line shifts from later edits don't resurrect a finding as "new." The same normalization drives the [feedback loop's](./feedback-loop.html) dismissal grouping, so a proposed suppression rule covers exactly the findings that share an identity. ### Line anchoring GitHub inline comments can only attach to lines that appear in the PR diff. When a finding's line doesn't: 1. A range with one valid endpoint collapses to that endpoint. 2. Otherwise inline snaps to the nearest commentable line within a short window, and adds a "📍 anchored to the nearest changed line" note. 3. If nothing anchors, the finding is suppressed and surfaced in the walkthrough's "Additional findings" section instead. ### Comment cap At most **12** findings are posted. When the model produces more, they're sorted by severity then confidence, and the lowest are dropped to the cap (still stored, still visible). This bounds the blast radius of a noisy review. ## Prompt-level discipline The gate is the backstop; the review itself does the first-line filtering. The reviewer role is explicit: - **A review with no findings is a SUCCESS.** Don't invent problems to look useful. - **Never** comment on style, formatting, naming, documentation, or test coverage. - **Refute your own finding** before flagging it — if you can talk yourself out of it, don't post it. - Calibrate confidence honestly against a rubric. ## Tuning The confidence floor and comment cap ship with sensible defaults. Severity threshold and custom instructions are set per-repo or per-workspace in the portal. If inline is too quiet, lower the threshold or the confidence floor; if too loud, raise them or add a [learning](./learnings.html) that teaches it to stop flagging a specific pattern. --- # The merge gate > The inline / review check run that can block a merge while open findings remain — off, report-only, or block by severity — and how a finding clears. # The merge gate inline can turn its review into a required status check, so a PR can't merge while unresolved findings remain. The gate is off by default, opt-in per workspace or per repo, and designed so it can never wedge a PR shut by accident. ## Modes The gate mode comes from the repo override, falling back to the workspace default (both default **off**): | Mode | Behavior | | --- | --- | | `off` | No check is posted. | | `report` | An always-passing check that carries the findings tally — informational only. | | `block-high` | Fails while any **high**-severity finding is open. | | `block-medium` | Fails while any **medium+** finding is open. | | `block-low` | Fails while **any** finding is open. | The check appears on GitHub as **`inline / review`**. Start with `report` to see what the gate *would* block before you make it required in branch protection. ## How delivery works The gate is posted per PR head, updated in place: - **GitHub App connections** create a real **Check Run**, one per head, updated as findings resolve. - **OAuth connections** can't create check runs, so inline posts a **commit status** with context `inline/review` instead. Syncing the gate is best-effort — a gate failure can never break the review pipeline itself. ## What counts as "open" Only genuinely actionable findings hold the gate. A finding blocks when it is: - **posted** (visible on the PR), and - **thread-anchored** (it has a resolvable GitHub comment thread), and - not yet **resolved**, **addressed**, or given a **feedback outcome**. A finding with no comment thread has no resolve affordance, so it can't hold a merge hostage — it's shown in the summary but doesn't block. Bot-authored PRs and heads that were never reviewed pass with a recorded skip reason, so a required check is never permanently stuck. ## How a finding clears There are two paths, both automatic: 1. **Resolve the thread on GitHub.** Resolving the review conversation notifies inline, which records the resolution and recomputes the gate. 2. **Change the flagged code.** A later push that touches the finding's lines marks it *addressed* — the fix is the proof — and the gate recomputes. Either way, inline re-evaluates the open findings for the head and updates the check. When the last blocking finding clears, the check goes green. ## Configuring it Set the gate mode in [review config](./review-config.html): a workspace default under **Review config**, and an optional per-repo override on the repository's settings. To make it enforced, add `inline / review` (or the `inline/review` status) to your branch protection rules on GitHub. --- # Repository memory > The per-repo profile inline distills from its own reviews and re-reads on every review — durable architecture, conventions, fragile areas, and gotchas. # Repository memory A good human reviewer knows the codebase. inline builds that knowledge automatically: after each substantive review it distills what it learned into a small, durable **repo profile**, and it re-reads that profile at the start of every future review. > Memory captures *implicit* knowledge inline discovered on its own — how this codebase is shaped and where it's dangerous. [Learnings](./learnings.html), by contrast, capture *explicit* rules a human taught it. The two are separate on purpose. ## What it holds The profile is Markdown with exactly four sections: ```markdown ## Architecture How the system is laid out; the major modules and how they relate. ## Conventions Patterns this codebase follows that a reviewer should respect. ## Fragile areas Code that breaks in non-obvious ways; where to tread carefully. ## Gotchas Surprises — footguns, implicit contracts, historical scar tissue. ``` It stays small on purpose — capped at a few thousand characters. It holds only durable knowledge: no PR-specific facts, no generic best practices that apply to any codebase. If it wouldn't help review the *next* PR, it doesn't belong. ## How it's built - **Absorb (incremental).** After each substantive review, a cheap model call folds that review's summary, posted findings, and changed paths into the existing profile. The inputs are tokens already paid for during the review, so absorbing is nearly free. This runs best-effort at the end of the pipeline — if it fails, the review is unaffected. - **Rebuild (full).** The portal's **Regenerate** button rebuilds the profile from scratch off the repo's most recent substantive reviews. Each profile tracks how many reviews it has absorbed, its cumulative cost, and when it was last updated. A profile can be hand-edited in the portal; once a human edits it, that's recorded so you know it's no longer purely agent-maintained. ## Where it's used The profile is injected into the review under a **Codebase profile** heading, alongside the diff rather than in the cached system prefix — so it can change per review without busting the [prompt cache](./review-cost.html#prompt-caching). The deep-review agent reads it before it starts reasoning about the diff, so it arrives already knowing the terrain. ## Controls - **Enable/disable** per repo (default on). - **Regenerate** to rebuild from recent reviews. - **Edit** the profile text directly in the portal. --- # The feedback loop > How inline learns from accepted, dismissed, resolved, and reacted-to findings — harvesting signals on PR close and proposing suppression rules for patterns your team rejects. # The feedback loop inline gets quieter and sharper the more your team uses it. It watches how you respond to its findings — resolve a thread, react with a 👎, change the flagged code, or merge without touching it — and turns those signals into outcomes, an acceptance rate, and proposed suppression rules. Reading these signals is deterministic and free: no model runs to read reactions. ## The signals Three signals, all read straight from GitHub: - **Thread state** — was the review conversation resolved or left open? - **Reactions** — 👍 / ❤️ / 🎉 on a finding's comment count as up; 👎 / 😕 count as down. Bot reactions are ignored. - **Code change** — did a later push touch the exact lines the finding flagged? ## Live, during the PR On each incremental review, prior open findings whose lines the new push touched are marked **addressed** — they stop counting against the [merge gate](./merge-gate.html), because changing the code is evidence the point landed. If a later review re-confirms the same issue, it's reopened. ## On PR close: the harvest When a PR closes, inline runs a feedback pass. It syncs thread resolutions, computes one diff per distinct reviewed commit, and resolves each finding to a single outcome: | Outcome | Condition | | --- | --- | | Rejected | 👎 present and ≥ the 👍 count. | | Fixed | The flagged code changed — the fix is the proof. | | Accepted | 👍 present, no code change. | | Dismissed | Thread resolved, no code change. | | Ignored | PR merged, finding untouched and unresolved. | | None | Closed unmerged, no signals. | Line matching uses a small fuzz against the base-side line map; file-level findings match on any change to their file. These outcomes power the acceptance-rate metric on the dashboard. ## Dismissal patterns → proposed learnings The loop's most useful output: when the **same finding pattern is dismissed or rejected across at least 3 distinct PRs within 90 days**, inline drafts a suppression rule. - Findings are grouped by category and a normalized title — the same normalization the [dedup fingerprint](./review-noise.html#dedup-fingerprints) uses, so a proposed rule covers exactly the findings that share an identity. - A single cheap model call drafts the rule, stored as a **proposed, inactive** [learning](./learnings.html) with the evidence attached. - One proposal per pattern, ever. Crucially, **inline never silences a class of finding on its own.** A proposed learning sits inactive until an admin approves it in the portal (which activates it) or deletes it. inline surfaces the pattern; a human decides. > This is the whole philosophy in one mechanism: the agent notices what you keep rejecting and offers to stop — but you stay in control of what it stops saying. ## Tuning The thresholds (3 distinct dismissals, a 90-day window) are built in. What you control is what happens next: review proposed learnings under **Learnings** in the portal and approve the ones that match your team's taste. --- # Learnings & skills > Two ways to teach inline — short taught rules (learnings) and authored expertise packs (skills), both folded into the review with progressive disclosure. # Learnings & skills inline's [memory](./repo-memory.html) is what it figures out on its own. **Learnings** and **skills** are how *you* teach it — the difference being size and structure. A learning is a one-line rule; a skill is a documented pack of expertise. ## Learnings A learning is a short, explicit convention inline applies on every review. Two ways they're created: - **Taught** — comment `@inline learn ` on a PR, and inline records it. ("We always use `zod` for request validation." "Never flag missing JSDoc.") - **Proposed** — the [feedback loop](./feedback-loop.html) drafts a suppression rule when your team repeatedly dismisses the same finding pattern. These arrive **inactive**; an admin approves or deletes them. Each learning carries: | Setting | Meaning | | --- | --- | | **Rule** | The convention text inline applies during review. | | **Scope** | This repository only, or the whole workspace. | | **Source** | Whether you taught it, or the feedback loop proposed it from dismissals. | | **Active** | Whether it's currently applied. | | **Evidence** | For proposals, the dismissals that justified it. | Manage them under **Learnings** in the portal: approve proposals, toggle active state, change scope, or delete. inline never activates a proposed learning itself — that's always a human decision. ## Skills A skill is a larger, reusable unit of review expertise. Where a learning is a sentence, a skill is a document — the right home for domain knowledge like "how we review database migrations" or "our API-versioning rules." Skills use **progressive disclosure** to stay cheap: 1. Every skill's **name and description** are always visible to the reviewer — a lightweight catalog it can scan on any PR. 2. The full **body** is loaded only when the reviewer decides that skill is relevant to the change in front of it. So a repo can have many skills attached without every review paying to read all of them — inline pulls in only the ones a given PR actually needs. ### Authoring A skill has a short **name**, a **description** (this is what inline matches against, so make it precise about *when* to use the skill), and a **body** of the actual guidance. Create and edit them under **Skills** in the portal. ### Attaching - **Workspace-wide** — the skill applies to every repo in the workspace. - **Per-repo** — attach a skill to just the repositories that need it. Skills resolve the same way for both the PR review pipeline and the [MCP ad-hoc review](./mcp.html), so a skill you author improves reviews everywhere inline runs. ## Which to use - A **rule** you can state in a sentence → a **learning**. - A **body of knowledge** with structure, examples, and conditions → a **skill**. - Something inline should discover and maintain itself → leave it to [memory](./repo-memory.html). --- # Code graph > Commit-anchored code-graph indexes that let the reviewer answer exact structural questions — who calls this, what's the blast radius — plus a 3D graph explorer. # Code graph The review agent's `search_code` tool does text matching. That's often enough — but some questions are structural, not textual: *Who actually calls this function? What's the blast radius of changing this signature? Which files import the one I'm editing?* inline answers those exactly by building a **commit-anchored code-graph index**. It is strictly additive. When an index exists, the reviewer gains four graph tools and a dependency-closure summary. When one doesn't — not built yet, disabled, or not configured — the review runs **byte-for-byte identical** to the pre-codegraph pipeline, falling back to live grep. A graph is never a dependency. ## What the index is A per-commit index holding a semantic graph of a repo's default branch: nodes and edges, queryable structurally. - **Node kinds:** File, Folder, Package, Function, Method, Class, Interface, Enum, Type, Module, Route, Variable, Field, Constant, Decorator, and more. - **Edge types:** calls, async calls, HTTP calls, usage, imports, uses-type, implements, inherits, defines, and file containment. It's built by a deterministic parsing engine — **zero AI tokens**. The only cost is a small amount of sandbox compute per build. ## How it's built Index builds run in an isolated sandbox: 1. Clone the repo at the exact commit — **incrementally** when a warm sandbox already has the history (re-parsing only changed files), else a cold clone. 2. Parse the codebase into the graph. 3. Compress and store the graph, plus a precomputed 3D layout. 4. Mark the index ready, then prune to the most recent few per repo. Builds are triggered by a **push** to the default branch (debounced), by **enabling** a repo, or by a **manual force** button. Live progress streams to the portal (queued → cloning → indexing → layout → uploading → ready), and the portal shows a "Rebuilding" strip that refreshes when the build completes. ## How reviews use it At review time inline resolves the PR head to the **nearest ready indexed ancestor** on the default branch, then overlays the PR's own changes: - If the head is exactly an indexed commit, no overlay is needed. - Otherwise it compares the index commit to the head and marks the changed files as an **overlay** — graph answers touching those files are flagged as possibly stale, since the index predates the edit. - If the comparison is too large or the branch diverged, the whole result is flagged stale but still offered. The overlay is always unioned with the PR's changed files, and every step is guarded — any failure just drops back to grep. ### The graph tools | Tool | Question it answers | | --- | --- | | `graph_find_definition` | Where is this symbol defined? | | `graph_find_references` | Everything that calls or imports this symbol (catches re-exports and renamed imports). | | `graph_who_imports` | Which files import this file? (blast radius) | | `graph_trace_calls` | Walk the call graph — callers or callees, to a bounded depth. | Results are prefixed with a staleness header when relevant, and rows touching overlay files get a ⚠ marker so the model weighs them accordingly. ### The dependency-closure section Beyond tools, inline injects a **dependency closure** into the review prompt: for the changed files, the set of files that import them. This tells the reviewer up front what a change might ripple into, without it having to ask. ## The 3D graph explorer Every index also powers an interactive explorer at **Repositories → (repo) → Graph**: a 3D scene of the codebase as a cloud of nodes (colored by kind, brighter with degree) and edges (colored by type), laid out by a deterministic force pass computed at index time. There's also an **"Ask the graph"** assistant — a streaming Q&A, powered by Claude, that answers structural questions about the codebase and highlights the relevant nodes as it reasons. ## Configuration Code graph is off unless enabled. Turn it on per repo with the **Code graph** setting in [review config](./review-config.html) (follows the workspace default when unset). You can also tune how many indexes are retained per repo and how often auto-rebuilds run. --- # Conversations > Talk to inline from a PR comment — ask questions, force a review, teach a rule, or resolve a thread — with every interaction logged in the portal. # Conversations inline isn't only a one-way reviewer. You can talk to it directly in a pull request by mentioning `@inline` in a comment. Every interaction is answered by the bot as the repo's posting identity and logged in the portal for observability. ## Commands | Comment | What it does | | --- | --- | | `@inline ask ` | Answer a question about the PR or codebase. | | `@inline full review` | Re-review the entire PR from scratch (ignore the incremental base). | | `@inline learn ` | Record a [learning](./learnings.html) — a convention to remember. | | `@inline resolve` | Resolve the finding thread it's posted in. | | `@inline help` | List available commands. | An `ask` runs a bounded agentic loop with the same read-only repo tools the reviewer uses (`read_file`, `search_code`, and — when configured — web research), so it can actually look at the code before answering rather than guessing. ## How it works A comment mentioning `@inline` fires a webhook that enqueues the command. Handling is idempotent on the comment — the same comment is never answered twice. The bot answers with Claude, bounded by a step cap so a conversation always terminates cleanly. ## The Conversations page Every command interaction is persisted and listed under **Conversations** in the portal, with: - the repo, PR, and commenter, - the command kind (ask / review / learn / resolve / help), - the question and inline's answer, - the model used, cost, duration, and status. Admins can filter by repo, kind, or status and search the text. It's the audit trail for everything anyone asked inline and everything it answered — useful for spotting recurring questions (which often make good [skills](./learnings.html#skills)) and for tracking spend on interactive use. --- # Configuring reviews > Every review setting — workspace defaults and per-repo overrides — for severity, identity, instructions, path filters, budget, and the optional modules. # Configuring reviews inline has two layers of configuration: **workspace defaults** and **per-repo overrides**. A repo left on "inherit" follows the workspace default; set any other value to override it for that repo. Set workspace defaults under **Review config** in the portal; set overrides on each repository's settings page. ## Review behavior | Setting | Default | What it does | | --- | --- | --- | | **Enabled** | — | Whether the repo is reviewed at all (per-repo only). | | **Severity threshold** | Medium | Findings below this severity are suppressed. Raise to High for mature repos; lower to Low for critical ones. | | **Review identity** | Bot | Post reviews as the inline bot, or as the connected user. | | **Custom instructions** | — | Free-text guidance inline applies during review. Team-specific rules that don't warrant a full [skill](./learnings.html#skills). | | **Path filters** | *(defaults)* | Extra path patterns to never review, added to the [built-in ignore list](./review-cost.html#1-path-filters-free). | ## The merge gate | Setting | Default | What it does | | --- | --- | --- | | **Merge gate** | Off | Off, Report-only, or Block by severity (high / medium / low). See [the merge gate](./merge-gate.html). | ## Budget | Setting | Default | What it does | | --- | --- | --- | | **Monthly budget (USD)** | — | Spend cap for the workspace. An alert fires at 80%. | | **Budget degrade** | — | Past the cap, stop at triage and mark reviews incomplete (so they get a full review next month) rather than skipping. | ## Optional modules (per-repo toggles) Each of these can be turned on per repo, or default from the workspace: | Toggle | Feature | | --- | --- | | **Walkthroughs** | Build a hosted [walkthrough](./walkthrough.html) page per PR. | | **Sandbox tests** | Run (and author) [tests in a sandbox](./sandbox.html). | | **Browser e2e** | Add browser end-to-end tests with video/screenshot evidence. | | **Auto-fix** | Offer verified [fix PRs](./auto-fix.html) for findings. | | **Graph index** | Build a [code-graph index](./codegraph.html) for the repo. | | **Breaking-change checks** | Cross-repo breaking-change detection. | ## MCP | Setting | Default | What it does | | --- | --- | --- | | **MCP enabled** | Off | Allow [pre-PR review over MCP](./mcp.html) for this workspace. | | **MCP monthly budget** | — | Org-wide and per-user spend caps for ad-hoc reviews. | ## Skills & learnings - **Skills** are attached workspace-wide or per-repo. See [skills](./learnings.html#skills). - **Learnings** are scoped to a repo or the whole workspace. Proposed learnings from the [feedback loop](./feedback-loop.html) wait for admin approval. --- # Auto-fix PRs > inline can open a stacked fix-PR that patches a review finding and verifies the patch in a sandbox before you ever see it. # Auto-fix PRs Finding a bug is half the job. inline can also *fix* it — opening a separate, stacked pull request that patches selected findings, and **verifying the patch by actually compiling and testing it in a sandbox** before presenting it. Nothing lands in your branch unless you merge it. > Two distinct fix engines share this pattern. This page covers **review auto-fix** (fixing review findings). For remediating confirmed dependency vulnerabilities, see **[Security auto-fix](./security-autofix.html)**. ## The workflow After a review posts, you choose which findings to fix — from the portal's review page, from a checkbox on the PR comment, or with a command. inline then delivers a fix by the least-intrusive route that works: 1. **A native GitHub suggestion** for a trivial single-hunk change. 2. **A stacked fix PR** — one commit per finding, on a branch opened against your PR's head branch. Merge it and the fix folds into your original PR. 3. **A patch artifact** you can download, for fork PRs inline can't push to. It never commits directly into the author's branch. ## Patch, then prove it The fix runs in an isolated [sandbox](./sandbox.html): 1. Clone the PR head, install dependencies, and record a **baseline** compile + test result. 2. For each finding, an agentic loop powered by Claude reads the code and edits files. If it can't fix something safely, it says so and skips it. 3. **Compile gate:** a fix is rejected only if it *regressed a check that was green at baseline* — otherwise the working tree is reset. Only files the agent actually changed are committed. 4. The test suite runs **once at the end**. A fix is marked *verified* only if tests didn't regress and it compiled; if the repo has no runnable checks, inline is honest and marks it *unverified* rather than pretending. Progress streams live to the portal and to a sticky PR comment (generating → verifying → pushing → ready). ## What you get Each fix run records, per finding, the patch (unified diff, additions/deletions), its verification status, and the commit. The fix PR's description summarizes what changed and how it was verified. You review it like any other PR — the point is that inline did the mechanical work and *checked its own work* first. ## Enabling & limits Off by default. Enable with **Auto-fix** in [review config](./review-config.html) (per-repo over workspace). Each run is bounded — it fixes a capped number of findings and is time- and cost-budgeted, so a run always terminates cleanly rather than running away. Requires the GitHub App to have **Contents: write** and **Pull requests: write**. Fork PRs fall back to a downloadable patch served by a share link. --- # The sandbox > Ephemeral microVMs where inline runs and authors tests, boots your app for browser e2e, and verifies fixes — with video and screenshot evidence. # The sandbox Some assurance can't be done by reading a diff — you have to *run the code*. inline runs code in ephemeral, isolated microVMs: it clones the PR, runs the existing tests, authors new ones where coverage is thin, and can boot your app for a real browser end-to-end pass — capturing video and screenshots as evidence. The sandbox also backs [auto-fix](./auto-fix.html) verification and [code-graph](./codegraph.html) builds. It runs off the review critical path. A sandbox run degrades to partial or failed — it never hangs a review. ## Environment Sandboxes boot from a prebuilt image with common runtimes and browsers preinstalled, so a run starts fast without waiting on a full toolchain install. A warm pool keeps idle boxes ready; each run cleans its clone before reuse. ## What a test run does 1. Fetch the diff, acquire a sandbox, and clone the PR head (works for forks too). 2. **Probe** the project — Node / .NET / Python / Go, lockfiles, existing test files, and monorepo layout — mapping changed files to the package that owns them. 3. **Plan** with a fast model: package manager, runner, an ordered step list (install → build → typecheck → lint → test), whether existing tests cover the change, and whether to author new ones. "No test runner" is not a dead end — it plans an install and hands off to authoring. 4. **Execute** steps within time and cost budgets. Only an install failure is fatal; output is classified per framework (Vitest/Jest/Mocha/.NET/pytest). 5. **Author tests** (optionally) with a Claude loop that can only write test files, when the change isn't already covered. ### Install resilience A large share of real-world runs used to end with zero evidence because an install failed. The sandbox has a fallback chain: out-of-memory is surfaced honestly; peer-dependency conflicts retry with legacy resolution; a flaky package feed retries ignoring failed sources; transient network errors retry; a missing `test` script rewrites to a direct runner invocation; and an "unrunnable" plan is rescued into an install-only plan from the lockfiles so authoring can still produce something. ## Browser end-to-end When enabled and the PR touches a runnable web app, inline runs a real browser pass: 1. **Boot the app** in the background and poll its URL until it answers. 2. inline writes the **browser test config itself** (never the model) — video on, screenshot on, trace on failure. 3. A Claude loop authors specs, runs them, and can **read failure screenshots back as images** to debug, repairing a couple of times. 4. If the app needs login and test credentials are configured, it authors a login and reuses the session; without them it runs unauthenticated and reports "login required." **Evidence** — videos, screenshots, traces — is stored (size- and count-capped) and attached to the run. ## Watching it live Each run has a share-link page at `/t/` that polls every few seconds and streams step output GitHub-Actions style. Video evidence is served with range support. The portal twin lives under **Reviews → (review) → Tests**. ## Secrets Test environment is resolved best-effort from committed `.env.test` / `.env.ci` / `.env.example` (keys only), layered under team secrets you store in the portal. Secret *values* are never surfaced — only which keys were available, recorded as a report artifact. ## Enabling & limits Enable **Sandbox tests** and **Browser e2e** in [review config](./review-config.html) (per-repo over workspace, both off by default). Runs are time-, cost-, and artifact-budgeted so they always terminate cleanly and never balloon in cost. --- # Walkthroughs > A hosted, layered diff viewer built for each PR — ordered change cohorts, Mermaid diagrams, visual recaps, and an "Ask inline" chat, shareable by link. # Walkthroughs A big PR is hard to read top-to-bottom. A **walkthrough** is a hosted, guided tour of the change that inline builds automatically: the diff reorganized into an ordered sequence of coherent layers, with diagrams, a visual recap of what changed for users, and a chat to ask questions — all on a page you can share by link. ## What it contains - **Layers.** Instead of alphabetical files, the PR is grouped into 2–6 cohesive change cohorts, ordered so you can read them as a story, each with its file ranges and a Mermaid diagram where useful. - **Visual recap.** For UI and API changes, before/after wireframes and data-model / endpoint cards summarizing the user-facing impact. - **Ask inline.** A streaming chat scoped to the PR's diff, so a reviewer can ask "why was this changed?" without leaving the page. ## How it's built inline builds the walkthrough in two passes powered by a fast model: one reorganizes the PR into ordered layers with diagrams, another produces the visual recap. The diff is then **frozen** into the walkthrough record, so the public page renders without any GitHub call. The placeholder in inline's PR comment is swapped for a signed link when the build finishes. ## Where it lives - **Public viewer** — `/w/`. The share token is the credential; the page is `noindex`. Anyone with the link can read it, no account needed. - **Portal twin** — **Reviews → (review) → Walkthrough**, org-scoped, which also exposes GitHub actions. The "Ask inline" chat is answered by Claude with a large diff budget and tight rate limits. ## Enabling Off by default. Turn on **Walkthroughs** in [review config](./review-config.html) (per-repo over workspace). Each walkthrough records its own cost like any other AI artifact. --- # MCP: pre-PR review > Review your changes before you open a PR — inline exposes an authenticated MCP server so coding agents like Claude Code can request a review of the working tree. # MCP: pre-PR review The best time to catch an issue is before the PR exists. inline exposes an **MCP server** (Model Context Protocol) so a coding agent — Claude Code, or anything that speaks MCP — can ask inline to review the working tree *while you're still writing it*, using the same pipeline that reviews real PRs. ## Connecting The server is a streamable-HTTP MCP endpoint at `/api/mcp`, authenticated with a per-user Bearer key: ```bash claude mcp add --transport http inline \ https://inline.dev/api/mcp \ --header "Authorization: Bearer ink_live_xxxxxxxx" ``` Mint a key under **Ad-hoc review** in the portal. Keys are prefixed `ink_live_`, shown once, and stored only as a hash. Each user can hold up to 10 active keys, with optional expiry (30 / 90 / 365 days). ## The tools | Tool | What it does | | --- | --- | | `review_changes` | Review a diff + files at a depth (`auto` / `local` / `deep`). Returns findings, cost, and a review ID. | | `get_review` | Fetch a prior ad-hoc review by ID. | | `list_pr_reviews` | List the reviews inline posted on GitHub PRs — scoped to the repo the agent is working in unless told otherwise. Filter by PR, branch, author, date window, text, and severity. Free. | | `get_pr_review` | Open one PR review in full: summary plus every finding with file, line, severity, and whether it's still open. Free. | | `whoami` | Identify the caller (free). | ## Working PR reviews locally `list_pr_reviews` closes the loop between the PR bot and the coding agent: the agent passes its own `git remote` as `repo`, gets back the pull requests that still have open findings, then pulls one with `get_pr_review` and fixes them in the working tree. Paste this into the repository's `CLAUDE.md` (or `AGENTS.md`) so the agent reaches for it without being told how: ```markdown ## Working with inline ### Before building a feature — get the plan reviewed For anything non-trivial, call `create_plan` first: wireframes, architecture, the files you'll touch, and any open questions. Share the returned link, then poll `get_plan_feedback` for pinned comments, answer them with `reply_to_plan_comment`, revise with `update_plan`, and only implement once the plan is approved. ### Before opening a PR — review the change Call `review_changes` with the unified diff plus the full contents of every changed file and the files they import. If the branch is pushed, pass the commit SHA as `ref` with `depth: "deep"` for a codebase-wide pass. ### After the PR is open — pull the review comments back down 1. Get this repo with `git remote get-url origin` and pass it as `repo`. 2. Call `list_pr_reviews` — it returns the pull requests that still have open findings. Add `branch` (`git branch --show-current`) for "my PR", or `since: "7d"` for a time window. 3. Call `get_pr_review` with the review id (or `repo` + `pr`) and fix the findings in the working tree. Always scope to this repository. Only pass another `repo`, or `all_repos: true`, if I explicitly ask about a different project. `whoami` reports what context applies if you're unsure whether this repo is connected. ``` Scoping is automatic — results stay inside the current project unless the user explicitly asks about another repo (`repo: "owner/other"`) or all of them (`all_repos: true`). Filters accept the loose forms a person actually says: `since: "7d"`, `"2 weeks"`, `"yesterday"`, or an ISO date; `branch` tolerates `origin/` and `refs/heads/` prefixes; `repo` resolves a bare repository name when it's unambiguous. Only open findings are returned by default — those still posted, unresolved, and untouched by a later push — with `only_open: false` / `include_resolved: true` to see everything, including what inline suppressed and why. ## Depths - **`local`** — review the attached working-tree files, with nothing pushed anywhere. Fully private to your machine. - **`deep`** — for a connected, enabled repo with a pushed ref, inline reads additional context through the org's GitHub installation. Either way it's the **same triage → deep-review pipeline** as the PR bot, with the repo's [memory](./repo-memory.html), [learnings](./learnings.html), guideline packs, and [skills](./learnings.html#skills) applied. A context-check handshake returns `need_context` (and spends nothing) when it needs files it doesn't have, so the agent can attach more and retry. ## Guardrails - **Admin-gated.** MCP is off until an admin enables it for the workspace. - **Budgeted.** Org-wide and per-user monthly caps. Cost is tracked per ad-hoc review. - **Bounded.** A few concurrent reviews per org, a time budget, and attachment caps (≤4 MB, ≤500 files). Admins enable MCP and set spend caps from the portal; users mint their own keys under **Ad-hoc review**. Every ad-hoc review is recorded with its depth, status, findings, and cost. --- # Sentinel: repo security > Continuous dependency and supply-chain security monitoring — vulnerability range-matching, malicious-package detection, agentic confirmation, and GitHub-native alert ingestion. # Sentinel: repo security Sentinel is inline's repository security monitor. It continuously watches your dependencies for known vulnerabilities and malicious packages, **confirms** each candidate with an agent that actually reads your code before it alerts you, and ingests GitHub's own security alerts into one place. Confirmed issues can flow straight into a [remediation PR](./security-autofix.html). It's an optional per-repo module, off by default. ## What it scans for - **Dependency vulnerabilities** — your exact lockfile dependencies are range-matched against public advisory data for npm and NuGet (every manifest listed under fingerprinting below). This is the primary signal. - **Malicious packages** — exact-name matches against a curated malicious-package feed. Always `critical`. - **Dependency fingerprinting** — dependencies are resolved from lockfiles first (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `packages.lock.json`), then from project manifests (`package.json`; `.csproj` / `.fsproj` / `.vbproj`, `Directory.Build.props`, `Directory.Packages.props` for central package management, and legacy `packages.config`) and hashed, so an unchanged manifest is skipped without re-matching. - **Threat news** — a web sweep surfaces relevant security news (informational, not code-specific). - **GitHub-native alerts** — Dependabot, code-scanning, and secret-scanning alerts are **ingested** via webhooks (opt-in) and stored pre-confirmed, with secrets always `critical`. Sentinel does not run its own SAST or secret scanner — it leans on public advisory data, the malicious feed, and GitHub's native scanners. ## Fresh vulnerability data Sentinel keeps its vulnerability data current on a schedule: security advisories (npm + NuGet), critical and high CVEs, the threat-news sweep, and the malicious-package feed. Advisory matching is queried live at match time, so you're always matched against the latest data. ## Agentic confirmation The point of Sentinel is **low noise** — a raw "you depend on a package with a CVE" is often a false positive because your code never hits the vulnerable path. So every candidate is confirmed by an agent that explores the repo (read-only, pinned at a commit, plus web search) and returns a verdict — `affected`, `not_affected`, or `needs_attention` — with file/line evidence and remediation. Confirmation is tiered for cost: a cheap fast model triages every candidate, a more capable model does the deep read only when a candidate looks serious or the first pass wasn't confident, and a frontier model is reserved for still-ambiguous high/critical cases. Advisories for the same package share one repo exploration, so cost tracks the *number of distinct packages*, not the number of advisories. A confirmed high/critical fires an alert immediately. ## Alerts Each alert carries its match type (`range` / `malicious` / `news` / `dependabot` / `code-scan` / `secret-scan`), a stable fingerprint, a status (`new → assessing → confirmed / not_affected / dismissed / resolved`), and — once assessed — the verdict, summary, evidence, and confidence. Manage them under **Security → Alerts** in the portal; the **Threat feed** shows the news sweep, and **Fixes** shows remediation runs with live progress. ## From alert to fix A confirmed, fixable alert can open a remediation PR automatically or on demand — see **[Security auto-fix](./security-autofix.html)**. Secret-scanning alerts are excluded from auto-fix (they need rotation, not a code change). ## Setup Enable per repo under **Security → Overview**, set the **Severity threshold**, and optionally turn on **Native alerts** to ingest GitHub's scanners. **GitHub App permissions:** Security events: read (for native alerts), plus Contents: write and Pull requests: write if you want [remediation PRs](./security-autofix.html). **Webhook events:** `dependabot_alert`, `code_scanning_alert`, `secret_scanning_alert`. Confirmed alerts can also notify [Microsoft Teams and email](./notifications.html). --- # Security auto-fix > Turn a confirmed Sentinel alert into a verified remediation PR — deterministic dependency bumps or an agentic patch, verified in a sandbox, on a convention-matched branch. # Security auto-fix When [Sentinel](./sentinel.html) confirms a vulnerability, inline can open a **remediation pull request** — bumping the vulnerable dependency or patching the code — verified in a [sandbox](./sandbox.html) before it's raised. It's the security counterpart to [review auto-fix](./auto-fix.html). ## What it fixes Fixable alert types: dependency range matches, malicious packages, ingested Dependabot alerts, and code-scanning alerts. **Secret-scanning alerts are excluded** — a leaked secret needs rotation, not a patch. ## Triggers - **Manual** — "Create fix" on an alert in the portal. - **Automatic** — when **Fix mode** is set to automatic and a newly confirmed (or newly opened native) alert meets the severity threshold, the dependency-only rule, and the open-PR cap. Each fix run atomically claims the alert, so two runs never race to open duplicate PRs. ## Two strategies The fix job runs in a sandbox and picks the safest route: 1. **Deterministic bump** — when the patched version is known and the dependency is direct, inline just runs the package manager's add command (`npm` / `pnpm` / `yarn`) at the fixed version. No model, no guesswork. 2. **Agentic patch** — otherwise a frontier-model loop upgrades, adds overrides/resolutions, removes a malicious package, or sanitizes vulnerable code — aiming for the minimal blast radius. ## Verify, then repair Per the monitor's **Verification** setting (none / build / full), inline plans a verification run, installs with the same [fallback chain](./sandbox.html#install-resilience) as the test sandbox, and runs it. If verification fails, it re-invokes the agent in **repair** mode for a couple of rounds. If it still fails, **no PR is opened** — inline won't hand you a broken fix. ## Convention-matched branches inline matches your team's branch naming. It reads recent branches and merged-PR heads to infer a prefix (`hotfix/`, `bugfix/`, `fix/`…), caches the convention, and names the branch accordingly. Base branch, draft state, and PR labels are all configurable on the monitor. On success the alert moves to `awaiting_review` with the PR linked. ## Live progress Every phase (`queued → cloning → analyzing → patching → verifying → repairing → pushing → opening_pr → done`) streams live to **Security → Fixes** in the portal, and to Teams/email if configured. ## Configuration On the repo's security monitor: | Setting | Meaning | | --- | --- | | **Fix mode** | Off / manual / automatic. | | **Fix severity threshold** | Minimum severity for automatic fixes. | | **Verification** | None / build / full check before opening a PR. | | **Dependency-only** | Only fix dependency issues automatically. | | **Max open fix PRs** | Cap on concurrent open fix PRs. | | **Base / target branch** | Where the PR is based and targeted. | | **Draft PR / labels** | Open as draft; labels to apply. | Requires the GitHub App to have **Contents: write** (to push the branch) and **Pull requests: write**. Each run has a bounded time and cost budget and a fixed number of repair rounds. --- # Pentest: red-teaming > Autonomous offensive-security agents attack a repository's own code in an isolated sandbox, prove exploitability with non-destructive PoCs, and surface only validated findings. # Pentest: red-teaming Pentest is inline's autonomous red team. AI agents attack a repository's **own source code** inside an isolated sandbox, **prove** exploitability with a non-destructive proof-of-concept, and surface only findings they could actually demonstrate. It's the offensive complement to [Sentinel](./sentinel.html)'s defensive scanning: where Sentinel asks "are we exposed to a known CVE?", Pentest asks "can I break this code myself?" It's an opt-in per-repo module. Every engagement runs against code the operator owns, in a sandbox, under enforced safety rules. > **The discipline:** prove, don't guess. One proven Critical beats ten speculative Lows. Non-destructive proofs only. Precision over volume. ## The multi-agent pipeline An engagement fans out across four phases: 1. **Enumerate** — a fast-model agent with read-only tools maps the attack surface: the stack, entry points, sinks, and auth model. This map is shared with every finder. 2. **Find** — one agent per enabled attack class, each focused exclusively on its class, tracing input from entry point to sink and returning candidate vulnerabilities. 3. **Validate** — candidates are ranked by severity then confidence, and the strongest go to a frontier-model agent with a screened command tool. It attempts a real, non-destructive PoC (it may install deps and start the app) and returns a verdict: validated or not, with the PoC, evidence, revised severity, and remediation. 4. **Report** — a deterministic step (no model) persists findings, computes surfaced vs. suppressed, and emails. ### Attack classes Twelve, each mapped to a CWE, all on by default: ```text injection (89) cmd-injection (78) broken authz (285) ssrf (918) xss (79) hardcoded secrets (798) deserialization (502) path-traversal (22) ssti (1336) xxe (611) open-redirect (601) auth weakness (287) ``` You can narrow the set per repo. ## Safety is enforced in code The safety guarantee is not a prompt request — it's a screened shell. The validation agent's command tool passes every command through a denylist that blocks destructive or exfiltration operations before they run: recursive `rm`, disk wipes, shutdown/reboot, fork bombs, `curl | sh`, reverse shells, raw device writes, `git push`, firewall changes, and more. Blocked commands return an error the model adapts to — they never execute, and every command is logged to the run's audit timeline. There's no network egress tooling by design. Additional guardrails: a per-run **cost cap**, validation count and time budgets, and **safe mode locked on** in v1. ## Findings Severity runs `critical / high / medium / low / info`. A finding **surfaces only if it was validated and meets the severity floor** — everything else is stored with an honest suppress reason (`unproven: …` or `below severity floor`), never silently dropped. Candidates the budget never reached are stored unproven too. Findings dedup by a `(category, file, sink)` fingerprint, so re-runs update rather than duplicate. ## The case file Every run produces a **case file** — used in the portal and on a public share page — that reads like a real pentest report: - A run header with status, trigger, and summary; a meta grid (validated / candidates / suppressed / cost). - **Validated findings** as cards: severity + CWE, the attack path (entry → data flow → sink), the proof-of-concept, evidence, and remediation. - A collapsible **agent decision timeline** from the run's log. - A collapsible **suppressed candidates** list with the reason each wasn't surfaced. The public report lives at `/p/` — read-only, `noindex`, no account needed. ## Running it - **Manual** — "Run now" from **Pentest → Settings**. An engagement already in flight is returned rather than stacked. - **Scheduled** — a sweep runs due configs (daily / weekly / monthly), atomically claiming each so two workers never double-enqueue. ## Configuration Admin-only, per repo: | Setting | Meaning | | --- | --- | | **Enabled** | Turn the module on. | | **Depth** | Light / tiered / deep. | | **Severity floor** | Minimum severity to surface. | | **Scan interval** | Schedule (daily / weekly / monthly); manual-only supported. | | **Cost cap** | Per-run spend cap. | | **Attack classes** | Which of the 12 classes to run. | | **Email alerts** | Email validated findings. | | **Safe mode** | Enforced command screening (locked on). | > **Status:** Pentest is inline's newest module. Config for routing validated findings into the auto-fix pipeline exists but that wiring is not yet active — findings are surfaced and shared today; automated remediation is on the roadmap. --- # Actions: CI/CD monitoring > Watch GitHub Actions runs — AI-triaged failures with root cause and suggested fix, flaky-test detection, and duration-regression alerts. # Actions: CI/CD monitoring Actions watches your GitHub Actions workflow runs and turns three kinds of signal into alerts: **failures** (triaged by AI into a root cause and a suggested fix), **flaky tests**, and **duration regressions**. It's an optional per-org module, off by default. The only AI spend here is failure triage; flaky and duration detection are deterministic. ## What it detects Every completed `workflow_run` is recorded (with its duration), then classified: - **Failure triage** — on a `failure` or `timed_out` run, inline pulls the failed jobs' logs (capped) and asks a model to categorize it (`build` / `test` / `lint` / `typecheck` / `deploy` / `dependencies` / `infra` / `other`), find the **root cause**, and propose a **suggested fix** with a confidence score. The result posts as a PR comment and, if configured, to Teams and email. - **Flaky tests** — a run that *succeeded only on a retry* (attempt > 1) raises a medium flaky alert. - **Duration regressions** — a successful run whose duration exceeds **1.5× the median of the last 10 successful runs** (and by more than a minute) raises an alert — `medium` past 2×, else `low`. A **branch filter** (empty = all branches) scopes what gets triaged. ## Alerts Each alert has a kind (`failure` / `flaky` / `duration`), a stable fingerprint, a status (`new / posted / dismissed / resolved`), and — for failures — the category, root cause, suggested fix, and confidence. Manage them under **Actions → CI alerts**, where failure alerts expand to show the root cause and fix. The **Overview** shows a 14-day window: success rate, alerts by kind, and triage spend. ## GitHub-native security alerts Dependabot, code-scanning, and secret-scanning alerts arrive on the same GitHub App connection, but they're handled by **[Sentinel](./sentinel.html)**, not here — even though you might think of them as "GitHub Actions security." Turn them on with **Native alerts** on the repo's security monitor. ## Setup Enable under **Actions → Settings** and choose which detectors run (failure triage / flaky / duration) and the branch filter. **Webhook event:** `workflow_run`. --- # Cloud monitoring > Provider-agnostic cloud posture, health, and spend monitoring for Azure — collectors over ARM REST, AI-triaged findings, and zero stored customer secrets. # Cloud monitoring Cloud is inline's CSPM — cloud security posture management. It scans your Azure subscription for security, reliability, cost, and operational issues; triages them with AI; and tracks resources, secure score, and spend over time. It's provider-agnostic by design (Azure first), and it stores **zero customer secrets**. Optional per-org module, off by default. ## How it reads Azure Nine collectors run against Azure's management APIs, each isolated so one failing doesn't sink the scan: | Collector | Looks at | | --- | --- | | **inventory** | Full resource inventory via Resource Graph. | | **defender** | Microsoft Defender secure score + unhealthy assessments. | | **advisor** | Azure Advisor recommendations (all five pillars). | | **policy** | Azure Policy non-compliance. | | **rbac** | Owner sprawl, service principals with Owner. | | **appservice** | HTTPS-only, min TLS, FTPS, always-on, cert expiry. | | **containerapp** | Failed/stopped apps, insecure ingress. | | **network** | NSGs exposing sensitive ports to the internet, orphaned public IPs. | | **cost** | Daily spend spikes (>1.5× the prior 7-day average). | ## Zero stored secrets inline authenticates with a **client-credentials grant against your tenant**, using inline's own multi-tenant Entra app — so inline holds only its own app secret, never a per-customer credential. Onboarding is one script you paste into Azure Cloud Shell: it registers inline's app in your tenant and grants it **Monitoring Reader + Security Reader** at the subscription scope (both free, read-only CSPM roles). Then you return to the portal and click **Validate**, which probes access and kicks off the first scan. ## The scan pipeline The worker sweeps due connections, claims a scan, and runs: collect → upsert resources → reconcile findings (dedup by fingerprint; auto-resolve anything a healthy collector no longer reports) → AI passes. **Two-tier AI triage** keeps it cheap: - A fast model batches findings and assigns a priority 1–4, suppressing obvious false positives. - A more capable model runs deep analysis on the top new high-priority findings only (capped per scan), producing an `az` CLI remediation runbook and risk context. Findings dedup by a stable fingerprint across scans, so a re-seen issue updates rather than duplicating, and one that disappears auto-resolves. ## The portal - **Overview** — posture cards, a secure-score dial, and a spend trend. - **Findings** — filterable, with AI priority, summary, and remediation; dismiss or suppress. - **Resources** — the live inventory. - **Connections** — the connect wizard and per-connection scan controls. ## Configuration Per-org settings: AI triage on/off, deep analysis on/off, **Severity floor**, **Scan interval** (default 6h), email alerts. **Azure RBAC required (in your subscription):** Monitoring Reader + Security Reader. --- # Observability > Runtime error monitoring — wrap any app in the inline SDK (or post the open envelope from any language), get grouped, symbolicated issues with AI root-cause analysis against the commit that shipped the bug. # Observability inline reviews code before it ships and watches the infrastructure it runs on. Observability closes the loop: it catches what your users actually hit in production. The mechanics are familiar if you've used an error tracker — an SDK reports exceptions, they're grouped into issues, you triage them. What's different is what happens next. inline already has authenticated, indexed access to the repository your app was built from, so an issue doesn't stop at a stack trace: an agent opens the real source **at the commit that produced the failing build**, follows the value that went wrong, and writes the patch. Optional per-workspace module. Nothing runs until you create a project. ## The shape of it ``` your app ──▶ POST /api/ingest/v1/ │ ├── symbolicate frames against uploaded source maps ├── fingerprint → group into an issue └── new or regressed? ├── Haiku triage → priority, category, one-line summary └── agentic root cause → the file, the line, a unified diff ``` Grouping happens **after** symbolication, so an issue keeps its identity and its history across deploys even though every chunk hash changed. ## Getting started 1. **Create a project** at *Observability → Projects*. One project per application. 2. **Link a repository.** Optional, and it's most of the value — without it, analysis is limited to what the stack trace alone shows. 3. **Install the SDK** (or post the envelope directly — see [the protocol](./observability-protocol.html)). 4. **Upload source maps from CI**, if you ship minified browser code. ### JavaScript / TypeScript ```bash npm install @pendral/inline-observe ``` ```ts import { init } from "@pendral/inline-observe"; init({ dsn: process.env.NEXT_PUBLIC_INLINE_DSN!, release: process.env.APP_VERSION, releaseCommit: process.env.GIT_SHA, // unlocks repo-grounded analysis }); ``` That single call installs global error and unhandled-rejection handlers and starts collecting breadcrumbs (console, fetch/XHR, clicks, navigation). Everything else is opt-out via `integrations`. **React** adds the component stack, which is what tells you *where in the UI* it broke: ```tsx import { InlineErrorBoundary } from "@pendral/inline-observe/react"; }> ``` **Next.js** wires the server, edge and browser through the framework's own instrumentation seams — no config wrapping, nothing to break on upgrade: ```ts // instrumentation.ts import { registerInline, captureRequestError } from "@pendral/inline-observe/nextjs"; export function register() { registerInline({ dsn: process.env.INLINE_DSN! }); } export const onRequestError = captureRequestError; ``` ```ts // instrumentation-client.ts import { init } from "@pendral/inline-observe"; init({ dsn: process.env.NEXT_PUBLIC_INLINE_DSN! }); export { onRouterTransitionStart } from "@pendral/inline-observe/nextjs"; ``` **Node** covers the process and your HTTP framework: ```ts import { installNodeHandlers, inlineErrorHandler } from "@pendral/inline-observe/node"; installNodeHandlers(); // uncaughtException + unhandledRejection app.use(inlineErrorHandler()); // mount after your routes ``` ### Everything else There is no first-party SDK for Python, .NET, Go or Ruby — there's something better: a documented JSON envelope over plain HTTP, and complete copy-paste integrations for each language generated with your real DSN on the project page. The smallest valid report is: ```bash curl -X POST "https://your-inline-host/api/ingest/v1/ink_pub_…" \ -H "Content-Type: application/json" \ -d '{"events":[{"message":"nightly import failed"}]}' ``` See [the protocol reference](./observability-protocol.html) for the full schema. ## Source maps Minified production stacks are unreadable without them, and the AI's fix quality collapses along with them. Upload on every deploy: ```bash npx @pendral/inline-observe sourcemaps upload \ --url https://your-inline-host \ --key $INLINE_WRITE_KEY \ --release $GITHUB_SHA \ --commit $GITHUB_SHA ``` The `--key` is the project's **write key** — the secret half of the credential pair, minted on the project page and shown exactly once. It is not the DSN and must never ship in a bundle. Pass `--commit`. Without it, symbolication still works, but the root-cause agent falls back to your default branch instead of reading the exact code that crashed. > Next.js needs `productionBrowserSourceMaps: true`; Vite needs `build.sourcemap: true`. ## Grouping One issue per distinct bug, not per crash. The fingerprint is: | Situation | Grouped on | | --- | --- | | Stack with in-app frames | Exception type + top in-app frames (module + function) | | Stack with only vendor frames | Exception type + top frames of any kind | | No stack | Type + normalized message (numbers, UUIDs, hex, URLs and quoted strings replaced) | | `fingerprint: [...]` supplied | Exactly what you passed | **Line numbers are deliberately excluded.** Adding an import at the top of a file shifts every line below it; if line numbers were part of the key, that one-line change would re-group every existing issue in the file and destroy its history — right when you most need it, during a regression. One consequence worth knowing: grouping runs on the **symbolicated** location, so the first deploy where you start uploading source maps re-groups the issues it affects once — `chunks/checkout-8f2c1a.js` and `src/checkout.ts` are genuinely different locations. It settles immediately after, and it's the right trade: every group from then on is keyed on a real file that survives rebuilds. Build hashes are stripped from paths for the same reason (`main-8f2c1a9b.js` → `main.js`), but only when the segment looks like a hash (≥8 characters *and* contains a digit), so `checkout-summary.js` is never collapsed into a neighbour's group. ## AI analysis Two tiers, so cost tracks impact: **Triage** (Haiku) runs on every new or regressed group. It assigns a priority 1–4, a category, and a one-sentence summary. It is opinionated about priority 4 — browser-extension frames, cancelled requests, cross-origin `Script error.`, offline users and bot traffic are noise, and saying so is what keeps the list readable. **Root cause** (Sonnet, agentic) runs on high-impact groups when the project is linked to a repo. It uses the same read-only repository tools as inline's code reviewer (`read_file`, `search_code`, `find_files`, `list_directory`), plus the [code-graph index](./codegraph.html) when one exists, pointed at the release commit. It produces: - the root cause, written in terms of the code it actually read - the file and line, with the real source shown inline - a unified diff you can apply - a confidence score, and verification steps An issue qualifies when triage rates it P1/P2, or when volume promotes it (enough events or enough distinct users). Volume can only promote, never demote — a rare crash on the payment path is exactly what a P1 verdict is for. You can always force a pass with **Re-analyze**. The card shows every tool call the agent made. If the analysis says a value is undefined at `checkout.ts:88`, you can see that it opened `checkout.ts` and read line 88. ### When it can't answer The agent is instructed to say so rather than guess: no in-app frames, a fault inside a dependency, or a file it couldn't localize all produce an explicit "here's what I can tell you" with no diff and low confidence. An overconfident wrong fix costs more than an admitted unknown. ## Lifecycle - **Unresolved → Resolved** manually, or automatically when an issue hasn't been seen for 14 days. - **Resolved → Regressed** the moment it's seen again. This re-opens the issue, marks it, and re-queues analysis. - **Ignored** stops it appearing in the default list without deleting anything. ## Retention and cost control | Control | Default | Where | | --- | --- | --- | | Minimum level | `info` | Settings (workspace) or per project | | Event retention | 30 days | Settings or per project | | Events kept per issue | 200 newest | Fixed | | Daily event cap | 50,000 per project | Per project | | Client sample rate | 1.0 | SDK `sampleRate` and per project | Retention only deletes raw event **bodies**. Issues, counts, and the hourly history buckets are never removed by retention, so a year-old regression still shows its true first-seen date and its full chart. Past the daily cap, occurrences still count toward the issue and its charts — only the individual bodies stop being stored. Your numbers stay honest; your storage stays bounded. ## Security The DSN carries a **public** key. It ships in browser bundles, so it is not a secret, and it grants exactly one capability: appending events to one project. It cannot read issues. Uploading source maps requires the separate **write key**, stored SHA-256-hashed — reveal original source and you need a real credential. Reading anything requires a portal session scoped to the workspace. The ingest endpoint is CORS-open by necessity (browser SDKs post from your origins) and credential-free by design — the SDK sends `credentials: "omit"`, so there is no cookie to protect. Abuse is bounded by a per-project-per-IP rate limit, a body-size ceiling, the daily cap, and length limits on every field in the schema. --- # Observability protocol > The open JSON envelope inline's error ingest accepts — every field, every default, and what a minimal client has to send. # Observability protocol This is the wire format the [observability](./observability.html) module ingests. It is deliberately small and fully documented so that a language without a first-party SDK is a copy-paste away rather than a support ticket. The canonical definition lives in `packages/core/src/observe/envelope.ts`. This page describes exactly that schema. ## Endpoint ``` POST /api/ingest/v1/ Content-Type: application/json ``` `publicKey` is the `ink_pub_…` credential from your project's DSN. It is public by design. - CORS is open (`Access-Control-Allow-Origin: *`); `OPTIONS` is handled. - Send **no credentials** — the endpoint ignores cookies, and sending them breaks the wildcard CORS response. - Success is `202 Accepted` with `{ "accepted": n, "dropped": n }`. ### Response codes | Code | Meaning | Should a client retry? | | --- | --- | --- | | `202` | Accepted (`dropped > 0` explains what was filtered and why) | No | | `400` | Malformed JSON or schema violation — the body names the field | No, it will never succeed | | `404` | Unknown project key | No | | `413` | Body over 1 MB | No, send smaller batches | | `429` | Rate limited | Yes, with backoff | | `5xx` | Server-side failure | Yes, with backoff | ## The envelope ```json { "sdk": { "name": "inline-observe.javascript", "version": "0.1.0" }, "sentAt": "2026-08-15T10:32:00.000Z", "environment": "production", "release": "1.4.0", "releaseCommit": "9f2c1ab…", "platform": "javascript", "events": [ /* 1–100 events */ ] } ``` Only `events` is required. `environment`, `release`, `releaseCommit` and `platform` at the envelope level are **defaults** applied to any event that omits them — so a batching client sends them once. Three shorthand forms are accepted, for the smallest possible integration: ```jsonc { "events": [ { … } ] } // canonical [ { … }, { … } ] // a bare array of events { "message": "boom" } // a single bare event ``` ### snake_case is accepted Every key is normalized, so `event_id`, `release_commit`, `in_app` and `context_line` parse identically to their camelCase spellings. `line_no` and `line` normalize to `lineno`; `col_no` and `column` to `colno`; `abs_path` to `filename`. Write idiomatic Python or Go without a translation layer. The keys **inside** `tags`, `extra`, `contexts`, `data` and `headers` are your data, not protocol, and are preserved verbatim. ## An event | Field | Type | Notes | | --- | --- | --- | | `eventId` | string | Your id, for support lookups. Optional. | | `timestamp` | ISO 8601 | Defaults to receipt time. Rejected if more than 7 days from now — a device with a wrong clock would otherwise pin the issue to 2044 and float it to the top of every list. | | `type` | `error` \| `message` | Inferred: `error` when `exception` is present, else `message`. | | `level` | `fatal` \| `error` \| `warning` \| `info` \| `debug` | Defaults to `error` for exceptions, `info` for messages. Below the project's floor ⇒ dropped. | | `platform` | `javascript`, `node`, `python`, `dotnet`, `go`, `ruby`, `java`, `php`, `rust`, `other` | Display only. | | `message` | string | Required if there's no `exception`. | | `transaction` | string | Route, job or component name — e.g. `POST /checkout`. Used as the culprit when no frame is in-app, and as the grouping key for stackless events. | | `environment` | string | e.g. `production`, `staging`. | | `release` | string | Must match what you upload source maps under. | | `releaseCommit` | string | The commit this build came from. **This is what points the root-cause agent at the right code.** | | `serverName` | string | Instance/host identifier. | | `exception` | object | See below. | | `breadcrumbs` | array | Up to 200, oldest → newest. | | `tags` | `{string: string}` | Filterable key/values. | | `contexts` | object | Free-form: `browser`, `os`, `runtime`, `device`. | | `extra` | object | Anything else. | | `user` | object | `id`, `email`, `username`, `ipAddress`. Hashed server-side into a counting key. | | `request` | object | `url`, `method`, `query`, `headers`. | | `fingerprint` | string[] | Grouping override. Wins over everything. | ### `exception` ```json { "exception": { "values": [{ "type": "TypeError", "value": "Cannot read properties of undefined (reading 'id')", "mechanism": { "type": "onunhandledrejection", "handled": false }, "stacktrace": { "frames": [ /* … */ ] } }] } } ``` `values` is an array so chained/caused-by exceptions have somewhere to live; the first entry is the one that groups and titles the issue. ### Frames — newest first > **This is the one place inline differs from what you may expect.** Sentry orders frames oldest-first, with the crash at the bottom. inline orders them **newest first**: `frames[0]` is where the error was thrown. Every reader — human or model — wants the crash site first, and it's also the order every JS engine already produces. | Field | Type | Notes | | --- | --- | --- | | `filename` | string | Absolute path or URL. | | `function` | string | Function or method name. | | `module` | string | Logical module, if your runtime has one. | | `lineno`, `colno` | number | 1-indexed line; column is needed for accurate source-map lookup on minified bundles. | | `inApp` | boolean | **Set this.** It decides grouping and what the AI reads first. `true` = your code, `false` = dependency/runtime. Inferred if omitted (paths containing `node_modules`, `.next`, `node:internal` etc. are treated as vendor). | | `contextLine` | string | The source line, if your runtime can read it. | | `preContext`, `postContext` | string[] | Up to 10 lines either side. | Server runtimes can usually fill in the context lines directly; for minified browser code inline recovers them from your uploaded source maps. ### Breadcrumbs ```json { "timestamp": "2026-08-15T10:31:58.220Z", "type": "http", "category": "fetch", "level": "warning", "message": "POST /api/checkout → 500", "data": { "status": 500, "durationMs": 812 } } ``` Ordered oldest → newest, ending at the error. In practice this is the fastest route to a reproduction — the culprit is more often the failed request two rows up than the frame that happened to throw. ## Limits | Limit | Value | | --- | --- | | Request body | 1 MB | | Events per envelope | 100 | | Frames per exception | 100 (deeper tails truncated) | | Breadcrumbs per event | 100 (newest kept) | | Rate limit | 120 requests/minute per project per IP | | Field lengths | Bounded per field by the schema; overlong values are rejected, not silently cut | ## Source-map upload ``` POST /api/observe/artifacts?release=&name=&commitSha=&environment= Authorization: Bearer Content-Type: application/json ``` Metadata in the query string, raw bytes as the body — so `curl --data-binary @file` works and no multipart parsing is needed anywhere. `name` is the URL path of the **bundle** (not the map), by convention prefixed with `~`: `~/_next/static/chunks/page-ab12.js`. inline reduces it to a match key the same way it reduces incoming stack-frame URLs, which is how the two meet. ## Worked example ```json { "sdk": { "name": "python-manual", "version": "1.0.0" }, "environment": "production", "release": "2026.08.15", "release_commit": "9f2c1ab7d4e", "events": [{ "level": "error", "platform": "python", "transaction": "POST /api/claims", "exception": { "values": [{ "type": "KeyError", "value": "'member_id'", "stacktrace": { "frames": [ { "filename": "app/claims.py", "function": "submit", "line_no": 88, "in_app": true }, { "filename": "app/routes.py", "function": "handle", "line_no": 42, "in_app": true }, { "filename": "site-packages/flask/app.py", "function": "dispatch", "line_no": 1502, "in_app": false } ] } }] }, "breadcrumbs": [ { "category": "db", "message": "SELECT member WHERE id=… → 0 rows", "level": "warning" } ], "tags": { "tenant": "acme" }, "user": { "id": "u_8123" } }] } ``` Reported this way, the issue groups on `KeyError` + `submit`/`handle`, shows the breadcrumb that explains it, counts one affected user — and if the project is linked to a repo, the root-cause agent opens `app/claims.py` at commit `9f2c1ab7d4e` and reads line 88. --- # Compliance > Track BAA and vendor-agreement coverage — detect which third-party providers your code sends data to, and whether a signed agreement covers that exposure. # Compliance Compliance answers a question that's easy to ask and hard to keep answering: **for every third-party service our code sends data to, do we have a signed agreement that covers it?** inline detects the providers your repositories use, cross-references your uploaded agreements (BAAs, DPAs), and flags real exposures — data actually flowing to a vendor you're not covered for. It's built for HIPAA-style obligations but the mechanics are general. Optional per-org, off by default. ## The domain - **Provider catalog** — a global profile per vendor: how it exposes data (`server_side` / `client_side_only` / `local_lib` / `hybrid`), whether the vendor *offers* a BAA, and detection signals (package names, API hostnames, config patterns). Seeded with ~60 curated providers and auto-extended by a web-research step for unknowns (which start `pending_review`). - **Vendor agreement** — *your* signed contract, uploaded as a PDF/DOCX. inline extracts its terms, dates, and covered services and tracks its status (`active` / `expiring` / `expired`). - **Compliance finding** — a per-repo exposure, judged on two axes: does data actually flow to the provider (`data_flows` / `no_data_flow` / `needs_attention`), and is sensitive data involved (`phi_likely` / `phi_possible` / `no_phi`). Real exposure = data flows **and** PHI is plausible. ## The pipeline Daily workers run four stages: 1. **Match** (no AI) — detect providers across dependencies and config files, classify each against your active agreements, short-circuiting on an unchanged manifest. 2. **Research** — for unknown vendors, a web search plus fast-model triage adds a catalog entry (pending human review). 3. **Analyze** — extract terms from an uploaded agreement document using a model with native PDF vision. 4. **Assess** — the same agentic false-positive killer as [Sentinel](./sentinel.html) (a fast triage model escalating to more capable models), reading the repo to decide whether data really flows and whether it's sensitive. It **escalates on a positive** finding rather than a negative one, because a wrong "you're exposed" is the expensive mistake. ## PR-time checks With **PR-time checks** on, inline also checks *at review time*: it parses the added lines of `package.json` / `.csproj` / config files in a PR diff, detects a newly introduced uncovered provider, and appends a `🔒 Compliance` note to the review — so a new vendor dependency gets flagged the moment it's proposed, not on the next daily sweep. ## The portal - **Overview** — a coverage matrix of providers against agreements. - **Agreements** — upload (≤25 MB PDF/DOCX), view extracted terms, re-analyze; expiry reminders fire at 30/7/1 days. - **Findings** — exposures with their two-axis verdict and evidence. - **Settings** — enable the module, PR-time checks, email alerts, and review the pending-provider queue. ## Configuration Agreement documents are stored in a private, access-controlled cloud container. Per-org settings: **Enabled**, **PR-time checks**, **Email alerts**. --- # Connecting GitHub > The two ways inline connects to GitHub — the org-wide GitHub App or per-admin OAuth — and how to choose between them. # Connecting GitHub inline needs access to your repositories to review pull requests and post its findings. There are two ways to grant it, and you can use whichever fits your organization. ## Option 1 — the GitHub App (recommended) Installing the **inline GitHub App** into your organization is the cleanest path: - Reviews and comments post under the **inline bot's own identity**, so they're clearly attributable and never tied to a person's account. - GitHub delivers pull-request events to inline **automatically** — no per-repo webhook setup. - You control exactly which repositories the app can see from GitHub's installation settings. Install it from the **Repositories** page in the portal, choose the repos to grant, and you're done. Enable the repos you want reviewed and open a PR. ### What the app can do The app requests only the permissions its features need: | Permission | Used for | | --- | --- | | Pull requests: write | Post reviews and inline comments. | | Contents: write | Open [auto-fix](./auto-fix.html) and [remediation](./security-autofix.html) PRs. | | Checks: write | The [merge gate](./merge-gate.html) status check. | | Issues: write | Respond to `@inline` [comments](./conversations.html). | | Actions: read | [CI/CD monitoring](./actions.html). | | Security events: read | Ingest Dependabot / code-scanning / secret-scanning alerts. | | Metadata: read | Basic repo information. | Features you don't use simply don't exercise their permissions. ## Option 2 — OAuth connection If you'd rather connect under a specific admin's GitHub account — for a smaller setup, or where installing an org app isn't an option — inline supports an **OAuth connection** from the portal. In this mode: - Reviews post under the **connected admin's** account. - inline **provisions the necessary repo webhooks for you** when you enable a repository, since OAuth connections don't get GitHub's automatic app-event delivery. - It needs repository and repo-webhook scopes, granted during the OAuth flow. Start it from **Repositories → Connect** and authorize in the pop-up. ## Choosing | | GitHub App | OAuth | | --- | --- | --- | | Posts as | inline bot | The connecting admin | | Event delivery | Automatic | inline provisions webhooks | | Best for | Organizations, teams | Solo/admin setups, restricted orgs | | Merge gate delivery | Check run | Commit status | Both connect the same product with the same features — the differences are identity and how events arrive. Most teams should use the GitHub App. ## Enabling repositories Connecting makes repositories **visible**; it doesn't start reviews. Go to **Repositories**, and toggle each repo you want reviewed to **enabled**. From there, each repo can override the workspace defaults for severity, merge gate, and the optional modules — see [review config](./review-config.html). --- # Organizations & teams > How inline separates work into organizations (workspaces) — the tenancy boundary for connections, repos, reviews, settings, and billing. # Organizations & teams An **organization** is inline's workspace and tenancy boundary. Everything — GitHub connections, repositories, reviews, findings, learnings, settings, and spend — belongs to exactly one organization. It's how a team's work stays separate from everyone else's. ## Personal vs. shared - Every user automatically gets a **personal organization** the first time they sign in — a private space to try inline against their own repos. - **Shared organizations** are for teams. Create one, connect GitHub, enable repos, and [invite](./members-invites.html) your teammates. ## Switching organizations If you belong to more than one, switch the **active** organization from the switcher at the top of the sidebar. Everything you see — repos, reviews, dashboards, settings — is scoped to whichever organization is active. ## What's scoped to an organization | Scoped per organization | | --- | | GitHub connections (App install or OAuth) | | Enabled repositories and their overrides | | Reviews, findings, conversations, and dashboards | | Learnings, skills, and repo memory | | Security, Actions, Cloud, Compliance, and Pentest configuration | | Notification channels (Teams, email) and MCP settings | | Monthly budgets and spend | Because the boundary is complete, two organizations never see each other's code, findings, or settings — even if the same person belongs to both. ## Members & roles People join an organization as **members** with a role that governs what they can change — see [roles & permissions](./permissions.html). Owners can rename the organization, manage members, and transfer ownership; admins manage the configuration; members work within it. ## Ownership transfer An owner can transfer ownership of a shared organization to another member — an atomic hand-off that swaps the owner role in one step, so there's always exactly one owner. Next: **[Roles & permissions](./permissions.html)** and **[Members & invites](./members-invites.html)**. --- # Roles & permissions > How inline governs who can do what — organization roles (Owner, Admin, Member) and the restricted developer role scoped to their own PRs. # Roles & permissions inline uses a small, clear role model. Sign-in is through your Microsoft work account; what you can *do* once you're in is governed by your role in the active [organization](./organizations.html). ## Signing in Everyone authenticates with **Microsoft Entra ID** (your work account) — there are no separate inline passwords. Sessions refresh your role periodically, so a role change takes effect without needing to sign out and back in. ## Organization roles Within an organization, each member holds one of three roles: | Role | Can do | | --- | --- | | **Owner** | Everything an Admin can, plus rename the organization, manage members, and transfer ownership. There's exactly one owner. | | **Admin** | Manage connections, enable/configure repos, change review and module settings, approve learnings, manage notification channels, and view spend. | | **Member** | Work within the organization — view reviews, findings, and dashboards, and interact with inline on PRs. | Most day-to-day configuration is an **Admin** action. Anything that changes the shape of the organization itself is reserved to the **Owner**. ## The restricted developer role Some people should only ever see **their own** work. inline has a confined **developer** role for that: a user restricted to a single **/me** view showing only the pull requests they authored, with no access to organization settings, other people's reviews, or the broader portal. A developer: - signs in with their Microsoft account as usual, - links their GitHub account so inline can match their authored PRs, - can mint their own [MCP keys](./mcp.html) for pre-PR review, and nothing else. It's the right role for a contractor or a large engineering org where most developers just want inline's feedback on their own PRs without the administrative surface. The role is assigned through [invites](./members-invites.html): invite someone as a confined member and they land in the developer view. ## Linking a GitHub account Linking is about **identity, not access** — it tells inline which GitHub login is you, so it can attribute your PRs, and (for developers) scope the /me view. It never grants inline new repository permissions; those come only from the [organization's GitHub connection](./connect-github.html). --- # Members & invites > Add teammates to an organization by email invite, assign a role, and link a GitHub account so inline can attribute pull requests. # Members & invites You bring people into an [organization](./organizations.html) by inviting them by email. Each invite carries the role the person will have when they accept. ## Sending an invite From the organization's member settings, invite a teammate by email and pick a role: - **Admin** — can manage connections, repos, settings, and other members. - **Member** — works within the organization. Invite a member as **confined** to give them the restricted [developer role](./permissions.html#the-restricted-developer-role), scoped to only their own pull requests. An invite is a one-time link that expires after **7 days**. It can be revoked before it's accepted. ## Accepting an invite The invitee opens the link, sees a preview of the organization they're joining, and signs in with their Microsoft work account. The email on the invite must match the account they sign in with. On acceptance they're added with the assigned role, and that organization becomes their active one. ## Linking GitHub For inline to attribute a person's pull requests to them — which the [developer view](./permissions.html) depends on — the user links their GitHub account once from their profile. This is an identity link only: it tells inline which GitHub login is theirs. It grants inline **no new repository access** — repo permissions come solely from the [organization's GitHub connection](./connect-github.html). ## Managing members Admins and the owner can change a member's role or remove them. The owner can also **transfer ownership** to another member. Removing a member revokes their access to the organization immediately; their history (reviews, findings) stays intact. --- # Notifications > Get inline's alerts where your team already works — Microsoft Teams channels and email — with per-category routing. # Notifications Beyond posting on the pull request, inline can push alerts to **Microsoft Teams** and **email** so the right people hear about a confirmed vulnerability, a CI failure, or a compliance gap without watching the portal. ## Alert categories Notifications are organized by category, so a channel only hears about what it cares about: | Category | Fires on | | --- | --- | | **Security** | Confirmed [Sentinel](./sentinel.html) alerts. | | **Compliance** | Confirmed [compliance](./compliance.html) exposures and agreement expiry. | | **CI/CD** | [Actions](./actions.html) failure, flaky, and duration alerts. | | **Pentest** | Validated [pentest](./pentest.html) findings and engagement summaries. | | **Digest** | Periodic roundups. | ## Microsoft Teams inline posts rich **Adaptive Cards** to a Teams channel through a Power Automate ("Workflows") incoming webhook: 1. In Teams, create a **Workflows** webhook for the channel you want, and copy its URL. 2. In the portal under **Settings → Notifications**, add a Teams channel, paste the URL, and choose which categories it should receive. 3. Send a **test** message to confirm it's wired up. Each channel records the status of its last send, so you can spot a broken webhook. The webhook URL is stored securely and never shown back in full. > inline uses the modern Power Automate Workflows webhooks, not the retired legacy Office 365 connectors. ## Email Confirmed high-severity findings and summaries can also go out by email. Recipients are resolved from each person's notification preferences, with per-repository opt-outs — so someone can follow security alerts for one repo without being paged for everything. ## Choosing what's noisy Every category is opt-in per channel. A common setup: a security channel that hears **Security** and **Pentest**, a build channel that hears **CI/CD**, and email digests for leads. Because inline only notifies on **confirmed** findings (not raw candidates), these channels stay signal, not noise. --- # Settings reference > A map of every settings surface in the inline portal — where each control lives and what it governs. # Settings reference A quick index of where to find things in the portal. Settings live at two levels: **workspace defaults** (organization-wide) and **per-repository overrides** (which fall back to the workspace default when left unset). ## Review config **Settings → Review config** — the defaults for how PRs are reviewed: - **Severity threshold** — the bar a finding must clear to be posted. - **Review identity** — post as the inline bot or the connected user. - **Custom instructions** — free-text guidance folded into every review. - **Path filters** — extra globs to never review. - **Merge gate** — off / report / block by severity. - **Monthly budget** and **budget-degrade** behavior. - **Reasoning effort** — how hard the deep review thinks. - Optional modules: **Walkthroughs**, **Sandbox tests**, **Browser e2e**, **Auto-fix**, **Code graph**, **Breaking-change checks**. - **MCP** — enable pre-PR review and set spend caps. See [configuring reviews](./review-config.html) for the details. ## Per-repository settings On each repository (**Repositories → a repo**): the same review settings as above, plus **enabled**, offered as overrides. Anything left as "inherit" follows the workspace default. ## Learnings & skills - **Learnings** — taught rules and proposed suppressions awaiting approval. - **Skills** — authored expertise packs and their attachment (workspace-wide or per-repo). ## Security & monitoring modules Each module has its own settings area: | Module | Where | Key controls | | --- | --- | --- | | [Sentinel](./sentinel.html) | Security → Overview | Enable, severity threshold, native alerts, fix mode. | | [Pentest](./pentest.html) | Pentest → Settings | Enable, depth, severity floor, schedule, cost cap, attack classes. | | [Actions](./actions.html) | Actions → Settings | Enable, detectors, branch filter. | | [Cloud](./cloud.html) | Cloud → Connections | Connect subscription, scan interval, AI triage. | | [Compliance](./compliance.html) | Compliance → Settings | Enable, PR-time checks, agreements. | ## Organization & people **Settings → Organization** and member management: - Rename the organization, transfer ownership (owner only). - [Invite members](./members-invites.html) and assign roles. - Manage [GitHub connections](./connect-github.html). ## Notifications **Settings → Notifications** — [Teams channels and email routing](./notifications.html) by category. ## Ad-hoc review (MCP) **Ad-hoc review** — mint your [MCP keys](./mcp.html); admins configure workspace enablement and budgets. --- # Security & trust > How inline handles your code and credentials — least-privilege access, sandbox isolation, enforced safety on offensive tooling, and human-in-the-loop control. # Security & trust inline reads your source code and acts on your repositories, so how it handles access and data matters. This page lays out the guarantees plainly. ## Access is least-privilege - inline's GitHub access comes only from the [connection you grant](./connect-github.html) — the GitHub App scoped to the repos you choose, or an admin's OAuth. It requests only the permissions its features use, and you can see and revoke that access from GitHub at any time. - Cloud monitoring uses **read-only** roles (Monitoring Reader + Security Reader) and authenticates against your own tenant, so inline holds **no long-lived credential to your cloud** — see [cloud monitoring](./cloud.html). - Linking a personal GitHub account is an **identity** link only; it never grants repository access. ## Your data stays in your tenancy The database and artifact storage live in your own cloud tenancy. Reviews, findings, code-graph indexes, sandbox evidence, and uploaded compliance documents are stored there, in access-controlled storage. Secrets you provide (test credentials, integration webhooks) are encrypted at rest and never shown back in full. ## Code runs in isolation Anything that executes your code — [sandbox tests](./sandbox.html), [code-graph](./codegraph.html) builds, [fix](./auto-fix.html) verification, and [pentest](./pentest.html) validation — runs in an **ephemeral, isolated microVM**, not on shared infrastructure. Each run is cloned fresh and torn down after. ## Offensive tooling is fenced in code The [pentest](./pentest.html) module attacks your own code, so its safety is enforced by the runtime, not by a prompt. The validation agent's shell is screened against a denylist that blocks destructive and exfiltration operations before they can run — recursive deletes, disk wipes, reverse shells, piping the internet into a shell, pushing to remotes, and more. There is no network-egress tooling. Proofs must be non-destructive. ## AI proposes, humans decide inline is built so a model never has unilateral authority over your repositories or your policy: - **Findings are suggestions.** You accept, dismiss, or ignore each one; nothing is forced. - **Fixes are pull requests.** Auto-fix and remediation open a separate PR you review and merge — inline never commits into your branch, and it verifies its own patch before offering it. - **Suppression rules need approval.** When the [feedback loop](./feedback-loop.html) notices a pattern you keep rejecting, it *proposes* a rule and waits — inline never silences a class of finding on its own. - **Findings are never silently dropped.** Anything suppressed is stored with a reason and visible in the portal, so you can audit what inline chose not to say. ## Signal over noise Every monitor confirms before it alerts — a raw "you depend on a package with a CVE" is validated by an agent that reads your code first. This isn't only a quality choice; it's a trust one. A tool that cries wolf gets muted, and a muted security tool protects nothing. --- # Privacy policy > What information inline collects, how it is used and shared, how long it is kept, and how to contact us. # Privacy policy **Effective October 15, 2026** inline is operated by Pendral Inc., a subsidiary of Evry Healthcare, Inc. This policy describes how we collect, use and share information about you ("Information" or "Personal Information") when you use inline (the "Services"). As used here, "we," "us" and "our" refer to Pendral Inc. Our Services are intended for a United States audience. Any information you provide, including any personal information, will be transferred to and processed by a computer server located within the United States. By using the Services, you consent to our collection, use, disclosure, and storage of information as described in this Privacy Policy. ## What we collect - **Account information.** Your name, email address and profile picture from Microsoft sign-in, or the email address you use for an emailed sign-in link. If you link a GitHub account, its GitHub user ID and username. - **Repository data.** Through the [GitHub connection](./connect-github.html) your organization grants, inline reads the source code, pull requests, diffs, issues, CI results and security alerts of the repositories you enable. - **What inline produces.** Reviews and their findings, walkthroughs, repository memory, code-graph indexes, plans, and the code changes (patches) behind fix pull requests. - **Agent run records.** For every AI run, inline keeps a record of the prompts, model responses, tool calls and their results. These contain fragments of your source code. - **Runtime error reports.** If you use [observability](./observability.html), the error reports your applications send, including stack traces and any context your application attaches. - **Connected services and uploads.** If you use [cloud monitoring](./cloud.html), configuration, health and cost information about the cloud resources you connect. If you use [compliance](./compliance.html), the agreements you upload. - **Security and activity logs.** Sign-in and sign-out events, sessions, and access activity, including IP address and browser user agent. - **Cookies.** inline uses cookies to sign you in and keep you signed in. ## How we use it We use this information to provide inline's features to you, to authenticate you, to communicate with you about your account and the alerts you configure, to secure the service and investigate misuse, to provide product support, to comply with applicable laws, regulations, and legal process, and to protect our rights and the rights of others. ## How we share it We do not rent or sell your Personal Information in personally identifiable form to anyone. We will only share your Information with third parties as outlined in this Policy and as otherwise permitted by law or as permitted with your consent. We use the following service providers to run inline. Each receives what it needs to perform its function for us: | Provider | What it does for inline | What it receives | | --- | --- | --- | | Microsoft Azure | Hosting, database, file storage and key management | All of the information above | | Microsoft | Sign-in, and sending emails such as sign-in links, invitations and alerts | Your name and email address; email content | | GitHub | The repositories inline reviews | Reviews, comments, checks and pull requests inline posts | | Anthropic | AI models that review code and run inline's agents, under a zero data retention arrangement: prompts and responses are not stored by Anthropic after the response is returned | Prompts containing source code, diffs and findings | | Daytona | Isolated environments that build and run your code | A copy of the repository being worked on | | Nango | Manages the GitHub authorization when an admin connects GitHub through OAuth | GitHub access tokens for that connection | | Exa | Web search when an agent looks something up | Search queries and the addresses of pages it reads. We do not send personal information to Exa | inline's database, file storage and caches are hosted in Microsoft Azure's South Central US region. If you configure notification destinations, such as a Microsoft Teams channel, inline sends alert content there. We may share Information in response to a court order, subpoena, search warrant, or to comply with law or regulation. We may also share Information within Pendral, including among affiliates, or with our parent company, or subsidiaries. If we (or our assets) are acquired, or if we go out of business, enter bankruptcy, or go through some other change of control, Personal Information could be one of the assets transferred to or acquired by a third party. ## How long we keep it - **Runtime error reports** are deleted after 30 days by default, or after the retention period set for the project. - **Reviews, findings, code changes and agent run records** are retained for the life of your account unless you request deletion. - **Account information and security logs** are retained for the life of your account unless you request deletion. We will retain and use your information to the extent necessary to comply with our legal obligations, resolve disputes, and enforce our legal agreements and policies. ## Your choices - You can see and revoke inline's access to your repositories from GitHub at any time. - **Settings → Privacy → Private by default** hides the plans, pre-PR reviews and agent runs you create from other members of your workspace, except workspace Owners. - To access, correct or delete your information, contact us at the address below. ## Protecting your information We maintain administrative, technical, and physical safeguards designed to protect the Information that you provide on our Services. These safeguards vary based on the sensitivity of the Information that is being collected, used, and stored. We cannot guarantee the security of our Services, nor can we guarantee the security of the Information you transmit to us over the Internet, including your use of email. ## Children We will not intentionally collect any personal information (as that term is defined in the Children's Online Privacy Protection Act) from children under the age of 13 through our Services without receiving parental consent. If you think that we have collected such personal information from a child under the age of 13 through our Services, please contact us immediately. ## Changes to this policy We may change this Policy at any time. If we do so, such change will appear on this page. Your continued access to or use of the Services constitutes your consent to these changes to this Policy. ## Contact us Contact us regarding this Policy or related privacy practices. If you believe we or any company associated with us has misused your Information, please contact us immediately. Pendral Inc.
contact@pendral.io
1-855-579-3879
PO Box 571208
Dallas, TX 75357 --- # Glossary > The vocabulary of inline, defined in one place. # Glossary **Organization (workspace)** — inline's tenancy boundary. Every connection, repo, review, and setting belongs to one. See [organizations](./organizations.html). **Connection** — the link to GitHub, either the org-wide GitHub App or an admin's OAuth. See [connecting GitHub](./connect-github.html). **Repository (repo)** — a GitHub repo inline knows about. *Connecting* makes it visible; *enabling* turns on reviews. **Review** — one pass over one pull request at one head commit. Reviews are [incremental](./review-cost.html#2-incremental-diffs) — each covers only what changed since the last. **Finding** — a single issue inline raised: a file, line range, severity, category, confidence, and body. Either *posted* to the PR or *suppressed* with a stored reason. **Triage** — the cheap first-pass classification of a PR as *trivial* or *substantive*, deciding whether to run the expensive [deep review](./review-pipeline.html#7-deep-review-a-frontier-model). **Deep review** — the full agentic review that reads files, searches code, and reasons before commenting. **Explorer** — a cheap subagent the deep reviewer dispatches to map a large PR breadth-first. **Validation gate** — the filter that suppresses low-confidence, below-threshold, duplicate, or un-anchorable findings before posting. See [noise control](./review-noise.html). **Severity** — a finding's impact rank: *low* / *medium* / *high* (plus *critical* / *info* in the security modules). **Confidence** — the model's self-assessed certainty in a finding, from 0 to 1. Below the floor, it isn't posted. **Suppressed finding** — a finding stored with a reason but kept off the PR. Never silently dropped; always visible in the portal. **Fingerprint** — a stable identity for a finding used to dedup it across commits and reviews. **Merge gate** — the `inline / review` status check that can block a merge while open findings remain. See [the merge gate](./merge-gate.html). **Memory (repo profile)** — durable per-repo knowledge inline distills from its own reviews. See [repository memory](./repo-memory.html). **Learning** — an explicit rule you teach inline (or approve). See [learnings](./learnings.html). **Skill** — an authored expertise pack loaded on demand during review. See [skills](./learnings.html#skills). **Feedback loop** — the mechanism that harvests accept/dismiss/react signals on PR close and proposes suppression rules. See [the feedback loop](./feedback-loop.html). **Code graph** — a commit-anchored index of a repo's structure that lets the reviewer answer exact "who calls this" questions. See [code graph](./codegraph.html). **Sandbox** — an ephemeral, isolated microVM where inline runs tests, browser e2e, and fix verification. See [the sandbox](./sandbox.html). **Auto-fix** — a verified fix PR for review findings. See [auto-fix](./auto-fix.html). **Sentinel** — the repository security monitor (dependency vulns, malicious packages, native alerts). See [Sentinel](./sentinel.html). **Security auto-fix** — a verified remediation PR for a confirmed security alert. See [security auto-fix](./security-autofix.html). **Pentest** — autonomous red-team agents that attack a repo's own code and prove exploitability. See [pentest](./pentest.html). **Actions** — CI/CD monitoring: failure triage, flaky detection, duration regressions. See [Actions](./actions.html). **Cloud** — Azure posture, health, and spend monitoring. See [cloud](./cloud.html). **Compliance** — BAA / vendor-agreement coverage tracking. See [compliance](./compliance.html). **Walkthrough** — a hosted, layered diff viewer built per PR. See [walkthroughs](./walkthrough.html). **MCP** — the authenticated Model Context Protocol server for pre-PR review inside coding agents. See [MCP](./mcp.html). **Developer role** — a restricted role scoped to a user's own pull requests. See [roles & permissions](./permissions.html). --- # For AI agents (llms.txt) > These docs are built to be read by LLMs and coding agents, not just humans — with clean Markdown endpoints and an llms.txt index. # For AI agents These docs are **AI-native**. Everything a human reads here is also available in clean, machine-readable form, so that LLMs, coding assistants, and agents can consume it accurately with no HTML noise to parse. ## Machine-readable endpoints | File | What it is | | --- | --- | | [`/llms.txt`](./llms.txt) | A compact index: the project summary plus a link to every page's Markdown. Small enough to load whole into a modest context window. | | [`/llms-full.txt`](./llms-full.txt) | The **entire documentation** concatenated as one Markdown file — for systems that can take the whole corpus at once. | | `‹page›.md` | Every page is also served as raw Markdown at its own `.md` URL (e.g. `review-pipeline.md`). | Each HTML page also declares its Markdown twin via ``, so a well-behaved fetcher can discover it automatically. ## Why this matters The same qualities that make docs good for humans make them good for models: **clear headings, short paragraphs, real tables, honest language, and one idea per section.** inline follows the emerging `llms.txt` convention so AI tools find the canonical source instead of guessing from rendered HTML. ([background on llms.txt →](https://llmstxt.org)) ## Driving inline as an agent If you're a coding agent, the most useful thing inline offers you is a **pre-PR review** over MCP: ask inline to review your working tree *before* you open the pull request, using the same pipeline that reviews real PRs. ```bash claude mcp add --transport http inline \ https://inline.dev/api/mcp \ --header "Authorization: Bearer ink_live_xxxxxxxx" ``` Then call `review_changes` with your diff and files. See **[MCP: pre-PR review →](./mcp.html)** for the tools, depths, and key management. ## The safety contract inline's own use of AI follows a rule worth knowing if you integrate with it: > **AI proposes, the pipeline verifies, a human approves.** Findings are suggestions; fixes are pull requests you review; suppression rules wait for approval; offensive tooling is fenced by an enforced denylist, not a prompt. See [security & trust](./security-trust.html). ## How these docs are maintained The site is generated from plain Markdown — one file per page, with a little front-matter. To add or edit a page you change Markdown and rebuild; the theme, syntax highlighting, search index, and these `llms.txt` files all regenerate automatically. That keeps the docs easy to keep correct, which is the real prerequisite for being AI-friendly: **version-accurate content beats clever formatting every time.**