Settings
Settings
Section titled “Settings”The settings page (/orgs/:customerId/settings) uses a tabbed layout:
- General — displays the organization name (editable by owners via inline click-to-edit) and the organization ID
- Members — team management with invite, role assignment, and member removal
- Roles — custom role management with granular permission matrix
- Teams — named groups of members whose granted roles are inherited by every member (visible with
teams:read; managed withteams:admin) - API keys — API key creation and revocation for dashboard/programmatic access
- Orchestrator keys — orchestrator API key management for Platform WebSocket connections
- Sources — read-only list of registered webhook sources (see below)
- Billing — plan and payment management
- CI trust — trust policy configuration for CI runs (visible with
ci_trust:readpermission) - Global workflows — org-level security knobs for cross-repo workflows (visible with
org_settings:readpermission) - Webhooks — outbound webhook endpoint management with delivery logs and test ping
- Event log — inbound webhook delivery log (visible with
event_log:readpermission) - Security — dashboard-level session and account security controls for this org (today, the session max age; viewing needs
org_settings:read, changing needsorg_settings:write) - Orchestrator security — read-only view of the orchestrator’s dashboard-write policy matrix (visible with
org_settings:readpermission) - Support access — opt-in switch that controls whether KiCI support staff may open read-only support sessions against your org (visible with
support:read; toggled withsupport:admin)
Audit-log-style entries are not a settings tab; they live on the dedicated Activity page accessible from the sidebar.
Tab selection syncs with the URL path (/settings/members, /settings/api-keys, etc.), making tabs bookmarkable.
General
Section titled “General”General settings show your organization’s basic information, including the org name (editable by owners) and the unique organization ID. Use this to rename your org or reference the ID for API calls and configuration.
Members
Section titled “Members”The members tab lets you manage your team:
- Invite new members by email.
- Assign roles.
- Suspend or remove members.
- Configure per-user CI trust levels.
Each member’s linked provider accounts (e.g. GitHub) are also visible here.
Roles define granular permissions across resource categories (runs, secrets, members, etc.) with 5 access levels: none, read, read_payload, write, admin.
Create custom roles to restrict what team members can do, or use the built-in Owner role for full access. The permission grid offers a per-column “set all” and a “reset all to none” for quick edits.
When you create or edit a role, you can only grant permissions you already hold — levels above your own role show a 🔒 in the grid and are rejected server-side, so a role can never hand out access beyond its author’s.
Teams are named groups of organization members. A role granted to a team is inherited by every member, so you can manage permissions for a whole group in one place.
Team names can also be referenced in workflow approval gates (approval: [{ team: 'leads' }]) — any member of the named team can satisfy that gate.
Managing teams (create / rename / delete, membership, role grants) requires the Teams permission at admin; read shows a view-only list.
API keys
Section titled “API keys”API keys allow programmatic access to the KiCI API for automation, scripts, and CI integrations.
Each key is scoped to this organization with a custom permission matrix and an optional expiry date. Keys can be revoked individually.
The permission matrix starts at none for every resource — you grant only what the key needs. Use a level column’s Set all button to apply that level everywhere at once, or Reset all to none to clear it. You can only grant up to your own role: levels above your ceiling are locked, and the server rejects any key whose permissions exceed yours.
Set a key’s kind to Agent in the creation modal (and give it an agent name) to mint a provenance-carrying service account: an agent org key drives the coding-agent MCP server and stamps its agent label on every audited action. Agent keys are marked with an Agent badge in the list so you can tell them apart from ordinary programmatic keys at a glance.
Use a key’s clone button to open the creation modal prefilled with that key’s name, expiry, and permissions — handy for recreating an expired key or deriving a new key from an existing one.
Orchestrator keys
Section titled “Orchestrator keys”Orchestrator keys authenticate the WebSocket connection between your orchestrator and the KiCI Platform relay.
Create a key here and set it as the KICI_PLATFORM_TOKEN environment variable in your orchestrator configuration. Keys can optionally be restricted to specific routing patterns.
Use a key’s clone button to open the creation modal prefilled with that key’s name and description.
The orchestrator keys tab manages API keys used to authenticate orchestrator-to-Platform WebSocket connections. These are separate from user API keys (which grant dashboard/API access).
List view — shows all active orchestrator keys with name, description, key prefix, creation date, and last used date.
Create — opens a modal to enter a name and optional description. After creation, the raw key is shown once in a copyable box. Set this key as the KICI_PLATFORM_TOKEN environment variable in your orchestrator configuration.
Revoke — opens a confirmation modal before soft-deleting the key. Any orchestrators using the revoked key will be disconnected.
Sources
Section titled “Sources”Webhook sources are registered automatically when an orchestrator connects to the Platform.
Each source shows its routing key and full webhook URL — configure this URL in your provider’s webhook settings (e.g. GitHub App).
GitHub App sources also show a kici-admin source get-webhook-secret <routingKey> command — run it on the orchestrator to retrieve the secret used to verify webhook signatures.
The sources tab shows webhook sources registered by connected orchestrators. Sources appear here automatically when an orchestrator connects to the Platform — there is no manual “add source” action in the UI.
Each source displays:
- Routing key — the source identifier (e.g.,
github:12345for a GitHub App,generic:my-sourcefor a generic webhook) - Webhook URL — the URL to configure in your provider’s webhook settings
- Registered at — when the orchestrator first registered this source
- Copy button — copies the webhook URL to the clipboard
Read-only — sources cannot be created, edited, or deleted from the dashboard. They are managed entirely by orchestrator connections. When an orchestrator disconnects, its sources remain visible (they are not automatically removed).
Empty state — if no orchestrator has connected yet, the tab shows “No webhook sources registered” with a link to the operator setup guide.
Webhook secrets — webhook secrets are not visible in the dashboard. They are configured on the orchestrator (see the operator guide), never in the dashboard, and are used to verify incoming webhook signatures.
Adding a new source requires:
- Configure a new provider in the orchestrator (e.g., add a GitHub App to the orchestrator’s provider config)
- Configure the webhook secret on the orchestrator (see the operator guide)
- Restart the orchestrator — it will register the new source with the Platform on connection
- Configure the webhook URL (shown in the sources tab) in the provider’s settings (e.g., GitHub App webhook URL)
Billing
Section titled “Billing”The billing tab shows your current plan (Free, Pro, Team, or Business), resource usage meters, and lets you upgrade to a paid tier.
Choose Monthly or Annual billing, click a tier’s “Upgrade” button to start a Stripe Checkout, or use “Manage payment” to switch tiers and update payment methods via the Stripe Billing Portal.
The tab also has a Billing email field — the address KiCI sends subscription messages to (a confirmation when your plan changes, and a notice if your plan is downgraded). A source badge shows whether it was set here (Manual) or synced from the payment provider (From Stripe). Set a billing email before upgrading from Free — the Upgrade buttons stay disabled until one is set. A billing admin can edit it any time.
The usage meters track:
- Members: invited users in this org.
- Orchestrator connections: direct WebSocket connections from your orchestrators to the Platform. Only coordinators (and standalone orchestrators) open a connection; peer/worker nodes in a Raft cluster share their coordinator’s connection and don’t count separately.
- Relayed webhooks (this month): webhooks delivered through the Platform relay during the current billing window.
- Live log minutes (today): live-log streaming time consumed in the current UTC day. On the Free tier this is capped at 60 minutes/day; paid tiers have no daily cap (shown as unlimited).
- Live-log tail-minutes (24h): live-log streaming time consumed in the trailing 24 hours, against the paid-tier rolling fair-use cap (Pro 5,000 / Team 20,000 / Business 50,000 tail-minutes). The Free tier has no separate tail cap (shown as unlimited) because it is bounded by the daily limit above. Only live tailing of a running job counts — stored and completed-run logs are never metered.
- Retention period: how long execution history is kept.
The infrastructure page may show a higher orchestrator count than this tab — diagnostics counts cluster nodes, billing counts billable connections.
The billing email is where KiCI sends subscription messages: a confirmation when your plan changes, and a notice if your plan is downgraded.
Set it before upgrading from Free to a paid plan. Once you subscribe, KiCI keeps it in sync with the email on file with the payment provider. A billing admin can edit it here at any time.
The orchestrator-connections counter measures the number of direct WebSocket connections that your orchestrator processes hold open against the KiCI Platform — one count per live connection.
What counts as one connection:
- One standalone orchestrator (single process, no cluster) → 1 connection.
- One Raft cluster (1 coordinator + N peers) → 1 connection — only the coordinator opens a Platform WebSocket. The peers gossip through the coordinator and never connect to Platform directly, so they do not count toward your billing limit.
- N independent orchestrator deployments (e.g., one per environment, one per region) → N connections.
This is why the infrastructure page can show more orchestrator nodes than the billing page shows connections: diagnostics counts every node in your topology (coordinator + peers), while billing only counts the WebSocket connections you pay for. A 4-connection org running two 3-node clusters and two standalones will show 4 on the billing meter and 8 on the infrastructure page — both numbers are correct, they measure different things.
When you hit the cap, the next coordinator that tries to connect is rejected; your orchestrator logs a plan-limit error. Existing connections are never disconnected. Upgrade your plan to lift the cap; the meter updates immediately.
The relayed-webhooks counter only includes webhooks delivered through the KiCI Platform relay — the route at kici.dev that verifies an inbound webhook and forwards it to your orchestrator.
Webhooks pointed directly at your orchestrator’s public ingest endpoint never reach the Platform, so they’re invisible to this counter and uncapped on every Hosted tier. If you have a public orchestrator ingress, you can mix-and-match: use the relay for sources you can’t expose publicly, and point GitHub (or any provider / generic webhook) straight at your orchestrator for the rest.
Every webhook the relay forwards counts — including ones your workflows ultimately ignore. Trigger matching runs on your orchestrator, not on the Platform, so the relay forwards each verified webhook before any trigger is evaluated. A source that sends many events you filter down to a handful of runs still consumes one relayed webhook per event. If a high-volume source mostly produces no run, point it directly at your orchestrator (see above) to keep it off this counter entirely.
When you hit the cap, new relayed webhooks are rejected with 429 Plan limit reached. Upgrade in the Stripe Billing Portal to lift the cap immediately; usage resets monthly on your billing anniversary.
Switch the prices shown on the tier cards between US dollars and euros. The choice you pick here is also the currency Stripe charges in when you click “Upgrade”.
The default is detected from your browser language. EU, EFTA, and UK locales default to euros; everywhere else defaults to dollars.
Your choice persists in a 90-day cookie (kici_pricing_currency), so it survives across reloads and applies on every billing page.
This banner appears when your organization’s latest payment to Stripe has failed. Your subscription remains active during the retry period, but you should update your payment method promptly to avoid service interruption.
CI trust
Section titled “CI trust”CI trust policy controls how your organization handles PR-triggered runs from different contributor types. Configure the default trust level for unknown contributors and set per-member overrides to control who can run workflows with full secrets access.
Global workflows
Section titled “Global workflows”Global workflows let a single “workflow repo” define jobs that run when events happen in other repos in the same org.
This tab exposes the security knobs as independent axes:
- Master enable toggle: turn the whole feature on or off.
- Authoring allow-list: which repos may define global workflows.
- Source deny-list: source repos whose events never trigger globals (forks, public-contrib).
- Elevated-access list: authoring repos that need source-repo secrets during execution.
See the user guide and the architecture reference for the full model.
Master kill-switch for global workflows in this org.
- OFF: the orchestrator will not register any workflow that declares
repos:patterns, and will not dispatch cross-repo triggers — effectively rolling the org back to per-repo-only semantics. All other settings on this page are ignored. - ON: the other toggles become your safety rails. Turn ON to opt in.
Restricts which repos in this org may define global workflows (the “authoring axis”).
- OFF: any repo in the org may declare a workflow with
repos:patterns and have it registered. - ON: only repos whose identifier matches one of the entries below may author globals. Non-matching repos have their global workflows dropped at registration time, with a warning in the orchestrator log.
- ON + empty list: no repo may author globals — use as a temporary lock-down.
Each entry has two parts:
- Source: pick a configured source (a specific GitHub App or universal-git source) to pin the entry to that source only, or leave it as Any source to match across every source in the org.
- Pattern: a glob matched against the authoring repo identifier (e.g.
myorg/ci-*,myorg/platform-*).
Pinning by source is useful when the same owner/repo could legitimately exist on more than one configured source and you only want to trust one of them as an author.
Deny-list for source repos whose events must never trigger a global workflow (the “source axis”).
Use this for untrusted territory — forks, public-contrib mirrors, sandboxes — where a single push shouldn’t be able to fan out org-wide automation.
Evaluated at dispatch time against the repo that emitted the event, independently of the authoring allow-list: a global workflow whose author is allowed will still be skipped if the source repo is denied. Both lists can be active simultaneously.
Each entry has two parts:
- Source: pick a configured source to deny only events delivered on that source, or leave it as Any source to deny across the org.
- Pattern: a glob matched against the source repo identifier (e.g.
myorg/fork-*,myorg/public-*).
Pinning by source is the right move when the same owner/repo is reachable through more than one configured source (e.g. a public forge and a trusted mirror) and you want to drop deliveries from only one of them.
Authoring repos listed here receive elevated access to source-repo secrets during global workflow execution.
- Without elevation: a global workflow job runs with only the workflow repo’s own credentials — it can clone both repos but can’t read the source repo’s scoped secrets.
- With elevation: the job gets the source repo’s secret context injected, so deploy / release / cross-repo automation flows work.
Treat elevated repos as effective owners of every source repo’s CI secrets — only add repos you fully trust.
Each entry has two parts:
- Source: pick a configured source to elevate only when the authoring repo lives on that source, or leave it as Any source to elevate across the org.
- Pattern: a glob matched against the workflow-authoring repo, not the source repo (e.g.
myorg/ci-deploy,myorg/release-automation).
Pinning by source narrows the trust window: if the same owner/repo is configured on more than one source, only the source you pick will grant elevation.
Webhooks
Section titled “Webhooks”Configure outbound webhook endpoints to receive notifications when runs and jobs change status. Each endpoint receives HMAC-SHA256 signed payloads with event details.
For each endpoint you can:
- Subscribe to event types:
run.started,run.completed,run.failed,job.started,job.completed,job.failed. - View delivery logs: HTTP response codes and retry counts.
- Send a test ping: verify connectivity before going live. A ping the endpoint accepts confirms with its HTTP status; a ping the endpoint rejects reports a warning and is recorded in the delivery log with the failure reason, so a broken receiver is never reported as a success.
Endpoint URLs must meet three requirements:
- HTTPS only. An endpoint URL must use
https:. Any other scheme is rejected when you save the endpoint. - Publicly routable address only. A URL that points at a private (RFC1918), loopback, link-local, unique-local, carrier-grade-NAT, multicast, or otherwise reserved address is rejected. Obvious cases are caught when you save; every delivery additionally resolves the hostname and connects only to the validated public address, so a name that resolves to a private address fails at delivery time with a generic “blocked” error. To receive notifications on a private network, put a publicly reachable relay in front of your receiver.
- No redirects. A delivery is never followed to a
Location:target — a receiver that answers with a3xxrecords that status as a failed delivery, with an error explaining that the endpoint redirected and that webhook targets must respond directly. Publish the final URL directly. Redirect failures count toward the consecutive-failure budget like any other failure, so an endpoint that keeps redirecting is eventually disabled automatically.
The delivery log shows recent webhook deliveries for an endpoint, including the HTTP status code, number of retry attempts, and the event payload.
Retry behavior:
- Deliveries are retried up to 3 times with exponential backoff.
- After 10 consecutive failures, the endpoint is automatically disabled — you can re-enable it from this view.
- At-least-once delivery: a delivery survives a Platform restart, so recovering an interrupted attempt can occasionally re-send one your receiver already processed.
- Deduplicate on
X-KiCI-Delivery: every attempt for the same delivery repeats that header value — treat it as the idempotency key in your receiver.
Notifications
Section titled “Notifications”Organization-wide notification channels, Slack connections, subscriptions, and the delivery log live on the dedicated Notifications page (in the org sidebar), on its Organization tab. The /settings/notifications URL redirects there.
Event log
Section titled “Event log”The event log shows every inbound webhook this organization has received, regardless of whether it came in via the Platform relay or directly to an orchestrator.
Each row shows the inbound webhook’s metadata and, with the right permission, its raw payload and processing outcome.
Filter by routing key, event type, status, or delivery ID. Click a row for the full detail plus the payload viewer.
The detail panel shows the inbound webhook’s full record:
- Delivery: where the webhook arrived and how it was routed.
- Outcome: what happened next — the matched workflow count and links to any runs it spawned.
- Payload: the raw webhook body, loaded on demand. Requires
event_log:read_payload.
Oversized payloads show an “omitted” badge.
The event log tab (/orgs/:customerId/settings/event-log) shows every inbound webhook this organization has received. The event log records, for each delivery: routing key, event, action, repo, status, processing outcome (processed / duplicate / lockfile_missing / failed), the matched workflow count, and the first run spawned (if any).
The list view supports filters for routing key, event type, status, and free-text delivery ID search. Click a row to open a detail panel with the full delivery record plus the payload viewer.
Permissions:
event_log:read— list rows and view metadata in the detail panel.event_log:read_payload— additionally view the raw webhook payload body. (Owners and admins inherit this. Lower-tier roles see “Payload not available” with a hint to ask for an elevated role.)
Edge cases the UI surfaces:
- Payload omitted — when the inbound payload exceeded the configured size cap, the row is still recorded with the payload shown as “omitted”.
- Orchestrator unavailable — when the orchestrator does not respond in time, the list still loads with the delivery metadata only, marked with an
orchestrator unavailablebanner. - Orchestrator-only deliveries — direct-ingress deliveries that never crossed the Platform appear marked
orchestrator_only.
Retention is 30 days.
Security
Section titled “Security”Dashboard-level security controls for this organization.
Session max age
Section titled “Session max age”Session max age controls how long a dashboard sign-in stays valid before the browser must re-authenticate. It applies to dashboard sessions only — CLI sessions are unaffected.
- Range: 1 hour to 30 days. The default is 7 days.
- Owner-gated: viewing needs
org_settings:read; changing needsorg_settings:write(the Owner role by default). - Enforced per organization: the limit is checked against the org whose data you are accessing, so a member of several organizations only re-authenticates when they touch data in an organization with a stricter limit. Re-authenticating restores access everywhere.
When a session exceeds the configured max age, the dashboard prompts for a fresh, full sign-in.
Orchestrator security
Section titled “Orchestrator security”Read-only view of the orchestrator’s dashboard-write policy.
Each row toggles one mutating dashboard action — setting a secret, approving a held run, retrying a dead-lettered webhook, and so on. The orchestrator operator decides which actions stay on the dashboard and which become CLI-only. The dashboard cannot change the policy itself — that’s the point: disabled actions stay off the dashboard entirely.
Manage the policy with:
- Show the full policy:
kici-admin org-settings dashboard-writes show - Disable an operation:
kici-admin org-settings dashboard-writes set --op <name>=false - Reset to permissive defaults:
kici-admin org-settings dashboard-writes reset
The summary strip at the top shows total / enabled / disabled counts plus whether your orchestrator is currently connected. A disconnected orchestrator means the page falls back to the cached policy from the most recent connection.
Support access
Section titled “Support access”Controls whether KiCI support staff may open read-only support sessions against your organization. Sessions are off by default — nobody outside your org can read your data until you opt in here.
When enabled:
- KiCI staff can open time-boxed, read-only sessions to investigate an issue.
- Every read they perform is recorded in your audit trail with the support reason.
- No writes are ever possible during a session.
Disabling the toggle immediately ends any in-progress support session. Only users with the support:admin permission (owners by default) can change this setting.
The Support access tab controls whether KiCI support staff may open a read-only support session against your organization to help diagnose an issue. The setting is off by default — until you opt in here, no one outside your org can read your data.
When support access is enabled:
- A KiCI operator can open a time-boxed (30-minute, renewable), read-only support session scoped to a stated reason.
- A support session is runs-only: the operator can browse your run list and, by confirming each run individually, view that run’s detail and step logs. Nothing else is visible, and no write is ever possible.
- Every run an operator opens is recorded in your Activity audit trail, attributed to the operator with the support reason — so you can see exactly what was looked at and why.
Disabling immediately ends any active session. Toggling the switch off closes every in-progress support session for your org at once. Enabling and disabling the setting is itself audited, attributed to the user who changed it.
Viewing the setting requires the support:read permission; changing it requires support:admin (granted to owners by default).