Skip to main content

Overview

Business Logic Validation checks that a pull request delivers what its task asks for. Kody finds the task the PR references, reads it from your task tracker, and lists every requirement with where it stands in the code. The result is one comment on the PR, kept up to date, the same on GitHub, GitLab, Bitbucket, Azure Repos and Forgejo. What the comment looks like on a PR that delivers part of its task:
Kody · Business Logic #291 · Ticket SLA badge — To fix: 2 missing requirements
After the fix, the same comment reads “All requirements met · ✅ 3 of 3 met”, with the earlier check kept below it.

Prerequisites

  • A task tracker connected in Plugins: Linear, Jira (Atlassian Rovo), Notion, Git Issues, or a custom plugin.
  • Kody only reads tasks by their id, and what they link to (a parent, sub-tasks, attached documents). It never searches for a task or writes to your tracker.
  • Without a tracker, you can still paste the task text in the command (see below).

Turning it on

Business Logic is on by default. Turn it on or off in Code review → What to review, on the Business Logic row, or in kodus-config.yml:
Click Business Logic on that row to open its settings, or use the row’s ⋯ menu: Edit opens the settings, Try it opens them at the test panel.

How Kody finds the task

Kody looks for task references in the PR title, branch name and description, in that order:
  • Keys like PROJ-123 (Jira, Linear and most trackers)
  • #123 and owner/repo#123 (Git issues; a number that is a pull request is ignored)
  • AB#123 (Azure Boards)
  • Links to Linear, Jira, Notion, GitHub/GitLab issues and Azure work items
A reference only counts once the tracker returns a task with that exact id, so UTF-8 or gpt-5 in a title are never mistaken for tasks. A lower-case key in the title (feat(kod-10)) counts when your tracker has that team or project; a Linear project id (P-KOD-1) never does. Kody also reads what the task links to:
  • A parent (a Linear sub-issue, a Jira sub-task, a ClickUp subtask): the PR is checked against the parent’s requirements this task’s title covers. A sub-issue that says “see the parent” is still checked.
  • Sub-tasks: a requirement one of them delivers shows as CHECK MANUALLY (“Delivered by KOD-20”), never as missing.
  • Documents attached to the task (Linear docs): read as part of the task, criteria included.

How the PR names the task

  • “Closes PROJ-1” or a key in the title or branch: the PR is checked against the whole task.
  • “Part of PROJ-1”: the PR delivers a slice. What’s missing is listed, but not as something to merge.
  • “Refs PROJ-1”, “see PROJ-1” or “related to PROJ-1” in the description: a mention. It is checked only when the PR names no other task, and then as the PR’s own.
  • Up to three tasks are checked per PR, one section each. A PR that states more (a release or a merge) is skipped.

The five states

Every row cites the file and line it is based on, and says what to change.

Before a gap is shown

A gap tells the author to redo work, so Kody holds each one to the code:
  • The requirement as the task writes it. An input or edge case the task never names (negative amounts, another code path, a format it doesn’t mention) never makes a row PARTIAL, and neither does what happens after the change (that an existing job sends the message the PR queues, that a route uses the serializer the PR fills in).
  • The code the PR calls, not only the diff. When a rule lives in code the PR calls but didn’t change (a validator, a helper, the mapper that builds a response), Kody reads it in the repository at the PR’s head before anything is shown, and does the same for every MISSING, PARTIAL and CHECK MANUALLY row. A row turns MET only on a file and line Kody read, and says it is already in the code, outside the diff. A row turns MISSING only when Kody read the code the PR relies on and cites the line that lacks the rule. Whatever the repository doesn’t settle stays as it was.
  • Work that belongs elsewhere. A requirement a sub-task delivers, or one your team guidance says isn’t checked here, stays CHECK MANUALLY and is never re-judged as missing.

On the pull request

  • Kody checks the PR on its first review. After that it re-checks when someone comments @kody -v business-logic or runs @kody review --force. Re-check can also be set to each push while something is missing, so a fix updates the comment without anyone asking, or to every push; each is one more validation per push.
  • Re-check any time with @kody -v business-logic. The same comment is edited; Kody never posts a second one.
  • A PR that meets its task gets a one-line comment (”✅ 4 of 4 met”), plus anything to check by hand, so the author knows it was checked. Turn off Comment when every requirement is met to stay quiet on those.
  • The comment is the signal on every platform: Kody doesn’t write a check or a status, so it never blocks a merge by itself. Its header says what is left to fix.

Replying to the comment

Reply to the Business Logic comment and mention @kody. Kody reads a comment as a reply when it is posted in that comment’s thread (GitLab, Bitbucket, Azure Repos), quotes it, or names the requirement, its state as the comment writes it (MISSING, PARTIAL) or the task id; any other comment goes to the chat.
  • Disagree: “It’s covered in useDrag.ts”. Kody re-checks what you pointed at and either marks it MET or says what it looked at and keeps it.
  • Accept a finding (someone other than the PR’s author: on GitHub, with write access to the repository; on GitLab, Developer or above on the repository; on Bitbucket, Azure Repos and Forgejo, a member of the organization the platform lists): “Keyboard reordering is out of scope, moved to SAA-102”. Kody confirms SAA-102 exists, marks the row ACCEPTED with who accepted it, and it is no longer left to fix. The decision stays on later re-checks, even when Kody words the requirement a little differently, as long as the task’s text is unchanged; once the task is edited, the requirement has to be accepted again.
What Kody answers:

When Kody stays quiet

Kody comments only when the author can do something about it: The reason for every skip is recorded and shown on the Business Logic settings page.

Running on demand

Comment on the PR (not on a line of code):
  • @kody -v business-logic: re-check the tasks the PR references
  • @kody -v business-logic PROJ-123 or a task link: check against that task
  • @kody -v business-logic followed by the requirements as text: check against what you wrote, no tracker needed

Settings

Open Code review → What to review and click Business Logic (or ⋯ → Edit). Every setting can be set globally and overridden per repository or directory.
  • Task source: every connected tracker (custom task plugins like ClickUp included), or one plugin. For a custom plugin, pick the tool that reads one task by its id; only read-only tools are offered. Use Try it, pinned on the right of the page (it needs permission to edit these settings): a task alone shows what Kody reads from it, and a pull request runs the whole check without posting, with the settings on screen, saved or not. Post to the pull request posts the result shown, without running it again, once per test; it refuses when the pull request got a commit after the test, so run the test again first.
  • Custom task id format (optional): a regular expression for ids Kody doesn’t find on its own: T(\d{4}) reads T1234 as task 1234. Keys like SAA-96, #12, AB#8, CU-… and tracker links are found without it, and so is a lower-case key like sc-123 in a branch name. In a title or description a lower-case key counts only when Linear or Jira has that team or project; for another tracker, set the format. A number the format captures is read as a Git issue only when Git Issues is the task source; with every connected tracker, T1234 is never issue #1234 of the repository.
  • Where acceptance criteria live: detected automatically (a criteria field, a checklist, or a list in the description), under a heading in the description, or in a custom field; a task without the field is read from its description. With Under a heading set to Acceptance criteria, this task is checked against its three bullets, and the paragraph above them is context:
  • Comment when every requirement is met (on by default): a PR that meets its task gets a one-line comment. Off, it gets none; gaps are still posted.
  • Ask for a task when the PR references none: Kody comments asking which task the PR is for (or pointing at the typo), instead of skipping it. PRs opened by bots, like Dependabot or Renovate, are left alone. A tracker that is down never counts.
  • Re-check: only on request (default), each push while something is missing, or every push. Each check runs on your organization’s model like a review does, so every push costs one validation per push.
  • Skipped pull requests: the ones code review skips are skipped here too: titles with an ignored keyword (ignoredTitleKeywords, like wip) and drafts when runOnDraft is off. A @kody -v business-logic comment always runs.
  • Team guidance: notes Kody follows when it judges, for example “Feature flags count as implemented when the flag exists and defaults to off”. It can’t change the verdict format or make Kody invent requirements.

Common setups

The same settings in kodus-config.yml:

From the CLI

A coding agent can check its work before opening the PR:
It checks your local changes against the task and prints one line per requirement and the status. With --format json (or --agent) it prints the same verdict structured, for an agent to act on. Nothing is posted to a pull request.

Cockpit

Cockpit → Delivered as asked shows the share of PRs that met their task, changes not in the task, how often developers agreed with Kody, and the split by who wrote the code (people or coding agents, from commit authors and Co-Authored-By trailers) and by team. It follows the Cockpit’s repository picker, and can be hidden in Organization → Cockpit like the other tabs.