Skip to content

Modules

Modules are reusable building blocks of configuration. A Lane doesn't hold tokens or service settings itself — it attaches modules, and each module points at a credential from Settings → Credentials. That indirection is the point: rotate a token or rename a channel in one place and every Lane using it picks up the change.

There are five module kinds. Two are required before a Lane can run; three are optional add-ons:

KindWhat it doesRequired?
TicketingWhere tickets are discovered (GitHub Issues, Jira Cloud, or Shortcut)Yes
Version ControlPush branches and open PRs (GitHub, Bitbucket Cloud, or Azure Repos)Yes
MessagingDiscord / Slack pings on PR opened or run failedNo
Coding StandardsInjects your house style into every workspaceNo
Agent Tuning (beta)Adds custom instructions to individual agentsNo

Looking for the Blueprints module? Per-repo codebase docs are no longer a module — they're the Lane-level Optimize feature now; see Optimize.

Every module shares the same anatomy:

  • A Name — yours to choose, shown everywhere the module is referenced.
  • An Enabled toggle — on by default; see disable vs delete below.
  • An Adapter, on kinds that talk to a service — chosen at creation and fixed afterwards (when editing, it shows as a read-only value). To switch providers, create a new module.
  • A Credential picker, on kinds that need a secret — select an existing credential of the matching type, or create one inline without leaving the form.

Ticketing

Defines a ticket source for Lanes to poll. Which tickets actually get picked up is decided on the Lane — its discovery labels (label trackers) or its Ready status (status trackers), not the module. The module is just "where to look and with what access."

AdapterTracker styleCredential
GitHubLabel-basedGitHub PAT
Jira CloudStatus-based (via transitions)Jira Cloud
ShortcutStatus-based (direct set)Shortcut

GitHub Issues

A label tracker: tickets are one repository's issues, and the run lifecycle is driven by labels.

  • Owner and Repo — the single repository this module watches. One module = one repo; watching a second repo means a second module.
  • API base URL (optional, GitHub Enterprise) — leave blank for github.com.
  • Credential: a GitHub PAT that can read, label, and comment on the repo's issues.

As a run moves through its stages, the Lane's label transitions add and remove labels on the issue, and progress comments are posted back to it. Which labels mark a ticket as AI-eligible — and which get applied or stripped at each stage — is all configured on the Lane, not here.

Jira Cloud

A status tracker: Lanes drive it by your native workflow statuses (Ready → In Progress → Done, etc.), so your Jira board reflects run progress without any Tenbi-specific labels.

  • Project key (optional) — scopes discovery to one project (JQL project = KEY). Blank = every project the credential can see.
  • Credential: a Jira Cloud credential — the site URL, account email, and API token all live there, not on the module.

Status moves go through Jira transitions. Tenbi resolves the transition whose destination matches the target status by name — which means the target must be reachable from the ticket's current status in your Jira workflow. If it isn't, the move is skipped and logged (the log names the transitions that were available); the run itself continues, but the ticket stays where it was.

The practical rule: the statuses you map on a Lane have to be connected in the workflow. If your workflow only allows Ready → In Progress → In Review → Done, a Lane stage that tries to jump a ticket straight from Ready to Done will silently leave it in Ready — fix the workflow (or the Lane's status mapping), not the module.

Shortcut

A status tracker too: Lanes drive it by workflow states.

  • No config fields beyond the basics — the module is credential-only.
  • Credential: a Shortcut API token.
  • Unlike Jira there are no transition constraints — a state is set directly by name, no reachability to worry about. Comments are posted, and labels can still be applied where a stage maps to one.
  • Discovery always skips archived stories. Completed stories are skipped only for label-based discovery — a status condition is taken at face value, since it may legitimately target a done-type state.

Version Control

Supplies the access a Lane uses to clone repos, push branches, and open PRs.

AdapterRepo namingCredential
GitHubowner/repoGitHub PAT
Bitbucket Cloudowner/repoBitbucket Cloud
Azure Reposproject/repoAzure DevOps PAT

All three adapters share one field:

  • Default base branch (overridable per Lane) — what PRs target when nothing more specific is set. The full precedence is per-repo → Lane → this module → main.

GitHub

  • Credential: a GitHub PAT with push + PR rights on every repo the Lane will touch.
  • API base URL (optional, GitHub Enterprise) — leave blank for github.com.

Bitbucket Cloud

  • Credential: a Bitbucket Cloud credential — account email plus an Atlassian API token.
  • No extra module fields beyond the base branch.

Azure Repos

  • Credential: an Azure DevOps PAT with Code read & write scope.
  • Azure DevOps organization — required. Repos are then entered per-Lane as project/repo (not owner/repo); the organization is set here, once.

One Version Control module is shared across all of a Lane's workspace repos, so the credential must be able to reach every repo on the Lane — the Verify button on each Lane repo row checks exactly that. Run it whenever you swap the credential or add a repo; it's much cheaper than finding out at clone time.

Messaging

Sends a ping to a channel at key moments. Adapters: Discord and Slack, each backed by a webhook credential — the webhook URL is the secret, so it lives on the credential (see webhooks in Credentials), not the module.

The module carries the channel identity; every field is optional:

  • DiscordBot username (optional) and Avatar URL (optional) override how the webhook's posts appear.
  • SlackChannel override (optional) posts somewhere other than the webhook's default channel, plus Bot username (optional), Icon emoji (optional), and Icon URL (optional, overridden by emoji).

Hooks are chosen on the Lane

Which events a module fires on is decided per Lane: when you attach it, you pick its hooks — PR opened, Run failed, or both (a newly attached module starts with both checked). The same module can be attached to many Lanes with different hooks on each, and a Lane can attach several Messaging modules — say, a team channel that hears about everything and an alerts channel that only hears about failures.

What the messages look like

  • PR opened — "AI opened PR(s) for ticket title", with the Lane name, the attempt number, links to each PR, and a link back to the run's record in Tenbi.
  • Run failed — "AI run failed: ticket title", with the Lane name, the failure reason, the state the run failed in, and the record link.

When telemetry was captured for the run, both messages append a compact cost line — dollar cost, tokens, turns, duration.

Delivery is best-effort by design: a rejected or unreachable webhook is logged and never fails the run. If pings stop arriving, check the webhook credential first — a deleted webhook fails silently from the run's point of view.

Coding Standards

A markdown document of your team's standards. When attached to a Lane, it's written into every repo of the workspace as CODING-STANDARD.md at provision time, and the agents treat it as a normative file — naming, patterns, things to avoid.

  • Markdown content — the document itself. This is the one required field; there's no adapter and no credential, because the module is the content.
  • A Lane attaches at most one Coding Standards module. The list page shows each module's content size, so you can tell a stub from the real thing at a glance.

Keep it focused: rules that change what the agent writes, not general philosophy. Concrete conventions — naming schemes, error-handling patterns, "never edit generated files" — earn their tokens; a page of engineering values does not.

Agent Tuning (beta)

Customizes the agents themselves. For each of the six agents — PM, Architect, Test Author, Developer, QA, and DevOps (see how the agents work) — you can write extra instructions in that agent's box, applied at run time.

  • All boxes are optional; leave an agent's box empty to keep it unchanged.
  • Overlays are additions only — they layer constraints on top of the standard agent behavior, never remove it.
  • No adapter, no credential. A Lane attaches at most one Agent Tuning module; the list page shows how many of the six agents each module customizes.

Use it for per-Lane working agreements: "always update the changelog," "prefer integration tests," "never touch generated files." Aim the instruction at the agent whose output you want to change — test conventions belong on the Test Author, deployment caveats on DevOps.

How Lanes attach modules

The module pages define the pieces; the Lane is where they're assembled:

  • Ticketing — required, exactly one. Pairs with the Lane's discovery conditions and its status or label mappings.
  • Version Control — required, exactly one, shared by every repo on the Lane.
  • Messaging — optional, any number, each attached with its own hooks.
  • Coding Standards — optional, at most one.
  • Agent Tuning — optional, at most one.
  • Optimize — not a module: a per-Lane toggle that builds curated codebase maps and serves them to the agents. See Optimize.

Creating and editing

Modules in the sidebar expands into one list page per kind — Ticketing, Version Control, Messaging, Coding Standards, Agent Tuning. Each page lists that kind's modules with a New module button (the empty state offers the same), and each row links through to the module's form.

A few behaviors to know:

  • Adapter first — on kinds with a provider choice, the adapter radios sit at the top of the form and decide which fields appear below. The choice is locked in at creation for every kind, Messaging included — a webhook URL is adapter-specific, so switching providers means a new module.
  • Inline credential creation — the credential picker only offers credentials of the type the kind + adapter needs, and lets you create a new one without leaving the form. Changing the adapter clears the selection, since a different adapter needs a different credential type.
  • Disable instead of delete — the Enabled chip on the list page toggles a module in place (the form has a matching checkbox). A disabled module is hidden from Lane pickers, so nothing new attaches to it — but Lanes already referencing it keep resolving it at run time; they just flag the reference so you know something's off. Disabling is how you retire a module gracefully, and how you stage a replacement without a hard cutover.
  • Deleting is protected — deleting asks for confirmation and cannot be undone, and a module still referenced by a Lane can't be deleted at all ("Cannot delete — referenced by one or more Lanes"). Detach it from the Lane first, or disable it and leave it be.