Skip to main content
Back to Blog
Guide
2026-09-28

Kiwi TCMS: Open-Source Test Management Guide

Kiwi TCMS guide for QA teams: deploy the open-source TCMS, model plans and runs, connect automation, and avoid migration traps in CI pipelines.

Kiwi TCMS: Open-Source Test Management Guide

Kiwi TCMS is an active open-source test management system for manual and automated testing. The latest official release I verified is Kiwi TCMS 16.5, published on September 17, 2026. It is not renamed or abandoned. The core repository is maintained under the kiwitcms/Kiwi GitHub organization, the documentation is published as Kiwi TCMS 16.5 docs, and the project still publishes release notes, container information, automation plugins, and commercial subscription options.

For QA engineers, the direct value is that Kiwi TCMS gives you a self-hostable system for test plans, test cases, test runs, execution results, bug tracker links, dashboards, reports, and automation imports. It is especially attractive when you want more ownership than a SaaS-only test-management tool gives you, or when your AI coding agents need a structured source of truth for regression scenarios, exploratory charters, and automation coverage.

The important caveat is packaging. The official Community Edition container image is a rolling public image, while version-tagged, multi-arch, and Enterprise images are available to subscribers. That is not a small operational detail. If your organization requires pinned production artifacts, you should plan either for a subscription, your own internal image mirroring policy, or a clearly documented rolling-image upgrade process.

Release And Packaging Reality

Kiwi TCMS 16.5 is a minor release with security-related updates and improvements. The release notes call out dependency updates, permission checks for uploaded files, visual login-page changes, and support for showing TestExecution attachments on the Test Run page when attachments are uploaded through the API. Enterprise 16.5-mt is based on Kiwi TCMS 16.5 and adds downstream features such as password-reset configuration, container tooling additions, and multi-tenant packaging changes.

ItemVerified current statusPlanning impact
Latest releaseKiwi TCMS 16.5, September 17, 2026Use 16.5 docs for new evaluations
Core sourcekiwitcms/Kiwi on GitHubCommunity code is inspectable and active
Core licenseGPL-2.0 in the main repositoryReview compatibility before embedding or redistributing modified versions
Public containerpub.kiwitcms.eu/kiwitcms/kiwi:latest rolling imageEasy trial, weaker reproducibility
Versioned imagesSubscriber-only according to release and container pagesNeeded for regulated pinned deployments
EnterpriseDownstream edition with PostgreSQL, add-ons, tenants, and GitHub app supportConsider for hosted, private tenant, or support needs

That packaging split is what many teams miss. "Open source" does not automatically mean "free versioned production container images forever." Kiwi TCMS is open source, and you can run Community Edition free of charge, but the project funds sustainability through subscriptions, private repositories, Enterprise images, hosted/private tenant options, support, and add-ons.

Deployment Shape With Docker

The official Docker installation docs recommend running Kiwi TCMS as a containerized production instance. Their examples use Docker Compose because it is the easiest way to get started, not because Compose is the only production shape. The docs point Kubernetes users toward the Helm directory in the source code.

For Community Edition, the Docker setup creates a web container and a MariaDB container. Enterprise uses PostgreSQL. Docker Compose also creates persistent volumes for the database and uploaded files. That split is the first operational decision to document: backups must include both structured data and uploads.

Deployment concernCommunity Edition defaultEnterprise note
Web applicationKiwi TCMS containerEnterprise container includes downstream add-ons
DatabaseMariaDB in official compose examplePostgreSQL in Enterprise
Public accessCan be reached through host FQDN or localhost for setupEnterprise requires FQDN, not raw IP address
Persistent dataDatabase volume and uploads volumeSame concern, often with tenant-aware storage
Upgrade commandPull image, restart, then run /Kiwi/manage.py upgradeTest upgrade on staging first

This minimal Compose file is intentionally conservative. It mirrors the documentation concept without pretending to replace the official examples. Use the official repository files as your baseline when building a production stack.

services:
  kiwi_web:
    image: pub.kiwitcms.eu/kiwitcms/kiwi:latest
    container_name: kiwi_web
    depends_on:
      - kiwi_db
    ports:
      - "8443:8443"
    environment:
      KIWI_DB_HOST: kiwi_db
      KIWI_DB_PORT: 3306
      KIWI_DB_NAME: kiwi
      KIWI_DB_USER: kiwi
      KIWI_DB_PASSWORD: kiwi
    volumes:
      - kiwi_uploads:/Kiwi/uploads

  kiwi_db:
    image: mariadb:latest
    container_name: kiwi_db
    environment:
      MARIADB_DATABASE: kiwi
      MARIADB_USER: kiwi
      MARIADB_PASSWORD: kiwi
      MARIADB_ROOT_PASSWORD: root-password
    volumes:
      - kiwi_db_data:/var/lib/mysql

volumes:
  kiwi_db_data:
  kiwi_uploads:

After the containers start, a new installation needs interactive initial setup. The docs use docker exec -it kiwi_web /Kiwi/manage.py initial_setup, and they warn that -t is often wrong for automated scripts because it allocates a pseudo-TTY. In CI or infrastructure automation, remove -t unless the command truly needs an interactive terminal.

docker compose up -d
docker exec -it kiwi_web /Kiwi/manage.py initial_setup
docker exec -it kiwi_web /Kiwi/manage.py showmigrations

For upgrades, the official flow is straightforward but non-negotiable: stop, pull, start, run upgrade, then check migrations. Skipping upgrade is the classic failure mode. The site may appear to boot while the database schema no longer matches the code.

docker compose down
docker compose pull
docker compose up -d
docker exec -it kiwi_web /Kiwi/manage.py upgrade
docker exec -it kiwi_web /Kiwi/manage.py showmigrations

The reader-visible command is simple, but the process around it is not. Take a database backup, preserve uploaded files, test the upgrade on staging, and record which image digest was running before and after. If you use the public rolling image, digest capture is your best reproducibility evidence.

Data Model That QA Teams Actually Use

Kiwi TCMS has many entities, but most teams live in a smaller workflow: Product, Version, Build, Test Plan, Test Case, Test Run, Test Execution, and Bug. Understanding the difference between a plan, a case, and a run prevents messy migration imports and unhelpful dashboards.

EntityWhat it representsAnti-pattern
ProductThe system or component under testCreating a product for every sprint
VersionProduct release line or branchUsing free-text version labels inconsistently
BuildConcrete tested build or deployReusing one build forever
Test PlanHigh-level strategy and groupingPutting every step in the plan document
Test CaseSpecific scenario with expected resultDuplicating the same case for every run
Test RunExecution container for selected cases against a buildTreating a run as a permanent backlog
Test ExecutionResult of a case inside a runUpdating status without comments or bug links

The official guide says a Test Plan should identify which features of a product will be tested and describe the overall strategy. It should not become the place for detailed execution steps. Put those in Test Cases. Test Runs are then created from selected, confirmed cases attached to a plan and a build.

This structure helps AI coding agents because it separates intent from execution. A plan can tell Cursor or Claude Code what business capability is under test. Cases provide scenario-level acceptance detail. Runs provide the current execution state. Without that separation, an agent sees a pile of inconsistent issue descriptions and produces automation that mirrors the mess.

Writing Cases That Survive Automation

A useful Kiwi TCMS case should be readable by a manual tester and reusable by automation. The docs emphasize setup instructions, clear actions, measurable expected results, and breakdown instructions. The measurable part is where teams often underinvest.

Case fieldWeak contentStrong content
SummaryLogin testLocked user cannot create a session
SetupUser existsUser locked-user@example.com exists and account status is locked
ActionTry loginSubmit valid password for locked account from the web login form
Expected resultIt failsResponse shows locked-account message, no session cookie is issued, audit event is written
BreakdownNoneDelete generated audit fixture if the environment does not auto-clean

If you are migrating from spreadsheets, do not import every row as a separate long-lived case. Normalize first. Remove duplicate variants that differ only by browser unless browser is the behavior under test. Use tags, components, categories, and plan membership to represent dimensions. Otherwise your first automation import will create hundreds of near-identical records that nobody trusts.

Here is a compact YAML format that a team can keep beside Playwright or pytest tests before syncing to Kiwi TCMS through the API. It is a team-owned staging format, not an official Kiwi import schema.

product: Billing Portal
version: 2026.09
plan: Subscription regression
cases:
  - external_id: billing-cancel-locked-user
    summary: Locked user cannot cancel a subscription
    category: security
    priority: high
    setup:
      - Account exists with active subscription
      - User account status is locked
    steps:
      - Open subscription settings
      - Attempt cancellation using valid credentials
    expected:
      - No cancellation request is created
      - User sees locked-account message
      - Audit event contains account_locked

The value is reviewability. A coding agent can transform that into UI tests, API tests, or API synchronization scripts, but a test lead can still judge whether the scenario is meaningful.

API And Plugin Automation

Kiwi TCMS exposes XML-RPC at https://your-kiwi-instance.com/xml-rpc/ and JSON-RPC at https://your-kiwi-instance.com/json-rpc/. The official docs strongly recommend tcms-api as the Python client instead of hand-coding direct RPC calls. The latest tcms-api docs show installation with pip install tcms-api, optional Kerberos support, a minimal ~/.tcms.conf, and direct constructor arguments supported after tcms-api v13.2.

[tcms]
url = https://tcms.example.com/xml-rpc/
username = api-bot
password = replace-with-secret
from tcms_api import TCMS

rpc = TCMS().exec

cases = rpc.TestCase.filter({'summary__startswith': 'Locked user'})
for case in cases:
    print(case['id'], case['summary'])

The server-side API docs show methods such as TestPlan.create(values), TestPlan.add_case(plan_id, case_id), TestRun.create(values), TestRun.filter(query), and TestRun.get_cases(run_id). That is enough to build a CI importer, but do not let an agent invent field IDs. Products, versions, builds, users, and plans should be looked up or created deliberately.

Kiwi also maintains automation framework plugins. The official organization pins repositories for junit.xml-plugin, pytest-plugin, robotframework-plugin, TAP, and JUnit. These plugins are not magic test runners. The project describes them as result parsers that talk back to Kiwi TCMS through tcms-api.

PluginVerified install or usageBest fit
kiwitcms-pytest-pluginpip install kiwitcms-pytest-plugin, then pytest -p tcms_pytest_plugin --kiwitcmsPython test suites that want direct reporting
kiwitcms-junit.xml-pluginpip install kiwitcms-junit.xml-plugin, then tcms-junit.xml-plugin /path/to/junit.xmlAny tool that exports JUnit XML
kiwitcms-robotframework-pluginpip install kiwitcms-robotframework-plugin, then Robot listener zealand.listener.KiwiTCMSRobot Framework suites
tcms-apipip install tcms-apiCustom synchronization, migration, and reporting scripts

The pytest plugin currently documents v15.4 as its latest release from April 27, 2026. The JUnit XML plugin documents v15.0 from September 23, 2025. The Robot Framework plugin page I verified still lists v12.7 from December 10, 2023 as its latest changelog entry, which is older but still an official repository. Pin and test plugin behavior before rolling it into release reporting.

python -m pip install tcms-api kiwitcms-pytest-plugin
pytest -p tcms_pytest_plugin --kiwitcms tests/
python -m pip install kiwitcms-junit.xml-plugin
pytest --junitxml reports/junit.xml tests/
tcms-junit.xml-plugin reports/junit.xml

The JUnit XML path is often the most portable because Playwright, Cypress, pytest, Jest, Maven, Gradle, and many CI systems can produce or transform into JUnit XML. The tradeoff is that XML loses some framework-specific context unless you encode it into names, properties, or failure text.

Robot And Pytest Mapping Details

Robot Framework has a convenient mapping pattern: test cases may specify a TC-xyz tag to map to an existing Kiwi TCMS TestCase. The plugin docs also show suite variables such as ${plan_id}, ${product}, and ${build_user_email}. If those are missing, the plugin attempts environment discovery based on the documented plugin behavior.

*** Settings ***
Documentation   Billing portal smoke suite
Library         OperatingSystem

*** Variables ***
${plan_id}      234
${product}      Billing Portal

*** Test Cases ***
Locked User Cannot Cancel Subscription
    [Tags]    TC-607    billing    security
    Should Be Equal    locked    locked

For pytest, decide whether the plugin should create or reuse cases from test names, docstrings, or explicit conventions. The v15.4 changelog says function docstrings are published as TestCase.text, which makes docstrings more important than usual. A generated test with a lazy docstring pollutes your TCMS. A precise docstring becomes useful living documentation.

def test_locked_user_cannot_cancel_subscription(api_client):
    """Locked user cannot cancel an active subscription.

    Expected result: the cancellation request is rejected, no subscription
    status changes are written, and an account_locked audit event exists.
    """
    response = api_client.post('/subscriptions/current/cancel', json={'reason': 'qa'})
    assert response.status_code == 423
    body = response.json()
    assert body['code'] == 'account_locked'

The test example asserts a side effect through the application response only. In a real suite, also query the subscription record or audit endpoint before reporting success. A result imported into Kiwi TCMS is only as trustworthy as the assertions that produced it.

GitHub, Jira, And Bug Tracker Integration

Kiwi TCMS supports internal bug tracking and external bug tracker integrations. The configuration docs list external tracker classes including Azure Boards, Bugzilla, JIRA, GitHub, GitLab, and Redmine, with Kiwi TCMS internal bug tracking available when the internal bug app is enabled. The administration docs say external bug trackers are configured through the admin interface under bug tracker settings, and implementation details live under tcms.issuetracker.

The integration scope is pragmatic:

CapabilityHow Kiwi frames itQA workflow
1-click bug reportCreate a bug from TestExecution when possible, fall back to a pre-filled browser windowFailed manual execution becomes a linked defect
Automatic bug updateLink existing bug reports back to TestExecution, often by commentAutomation failures can carry traceability
Bug info displayShow contextual information on pages that display bugsTest run review does not require opening every tracker tab
Configurable trackersDotted classes in EXTERNAL_BUG_TRACKERSAdmins can restrict or extend tracker options

For GitHub specifically, there is an official kiwitcms/github-app repository. Its README states that the add-on is designed for Kiwi TCMS Enterprise and multi-tenant environments, communicates from GitHub through webhooks, and can add repositories as products, configure BugSystem records, skip forks, and add git tags as product versions. That is materially different from the simpler built-in GitHub issue tracker class.

For Jira, verify your actual deployment configuration. Kiwi TCMS has a JIRA integration class in the documented tracker list, and additional tracker integration is provided through add-ons. But Jira instances vary wildly across Cloud, Data Center, permissions, custom required fields, and workflow validators. A 1-click bug flow that works in a demo can fail in production if Jira requires fields Kiwi cannot infer.

CI Reporting Pattern

The safest CI pattern is to treat Kiwi TCMS as the durable test-management record, not as the place where flaky automation is laundered into legitimacy. Run your tests, produce trustworthy results, import them, and fail the pipeline based on the test runner or a verified API response.

This GitHub Actions workflow uses current action majors and imports JUnit XML after pytest runs. It avoids shell variables inside with: inputs and keeps secrets in GitHub Actions secrets.

name: python-tests-to-kiwi

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7

      - uses: actions/setup-python@v7
        with:
          python-version: '3.12'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install pytest kiwitcms-junit.xml-plugin

      - name: Run tests
        run: pytest --junitxml reports/junit.xml tests/

      - name: Report to Kiwi TCMS
        env:
          TCMS_API_URL: ${{ secrets.TCMS_API_URL }}
          TCMS_USERNAME: ${{ secrets.TCMS_USERNAME }}
          TCMS_PASSWORD: ${{ secrets.TCMS_PASSWORD }}
          TCMS_PRODUCT: Billing Portal
          TCMS_PRODUCT_VERSION: main
          TCMS_BUILD: ${{ github.sha }}
        run: tcms-junit.xml-plugin reports/junit.xml

If you use this with an AI coding agent, ask it to preserve the source of truth. It may add a new test file and a workflow, but it should not silently create new product names, versions, or builds on every run without your naming rules.

Migration From TestRail, Spreadsheets, Or SaaS Tools

Kiwi TCMS is a realistic destination when your team wants open-source control, self-hosted data, and automation import options. It is not automatically a drop-in replacement for every SaaS workflow. Before migration, map concepts.

Source conceptKiwi TCMS targetMigration decision
SuiteProduct, plan type, or parent planAvoid creating one product per suite unless suites are separate products
SectionTest Plan hierarchy, category, component, or tagPick one primary navigation model
CaseTest CaseDeduplicate variants before import
MilestoneVersion or Build depending on meaningUse Version for release line, Build for tested artifact
RunTest RunImport only active or historically valuable runs
Defect linkBug linked to TestExecutionValidate tracker URLs and permissions first

Teams comparing tools should read broader market context like best test management tools beyond TestRail, then evaluate Kiwi against their constraints. If the priority is managed workflow, vendor support, and a polished SaaS experience, a commercial platform such as PractiTest may be a better fit. The PractiTest test management guide is the right comparison point for that path.

The open-source advantage is control. The cost is operations. Someone owns the database, backups, upgrades, authentication, email, TLS, bug tracker credentials, plugin versions, and data hygiene. If nobody wants that job, hosted or commercial options may be cheaper in practice.

Failure Mode: The Upgrade That Looks Fine Until Execution

A realistic Kiwi TCMS failure mode goes like this: the team uses the rolling Community image, runs docker compose pull, restarts containers, sees the login page, and assumes the upgrade is complete. Two days later, testers cannot update executions or automation imports fail with server errors. The root cause is that /Kiwi/manage.py upgrade was skipped, so migrations and post-upgrade adjustments did not finish.

Diagnosis should be systematic:

  1. Check the running image digest and release notes.
  2. Run showmigrations and verify no migrations are pending.
  3. Inspect web container logs around the failing request.
  4. Reproduce with a small API call, not the full automation plugin.
  5. Restore staging from backup and replay the documented upgrade flow.
docker inspect kiwi_web --format '{{.Image}}'
docker exec -it kiwi_web /Kiwi/manage.py showmigrations
docker logs kiwi_web --tail 200

That first command uses Docker's Go template syntax, not a shell variable. It should print the image ID for the running container. Capture it with your release evidence when using rolling images.

What People Get Wrong With Kiwi TCMS

The biggest mistake is treating Kiwi TCMS as a passive document dump. If you import messy spreadsheets, never confirm cases, never close obsolete plans, and let automation create inconsistent products or versions, the tool will faithfully preserve confusion. Test management systems amplify discipline. They do not create it by themselves.

The second mistake is over-automating the wrong layer. Automation plugins should report trustworthy results. They should not be the only place your test taxonomy exists. Keep naming rules, product/version/build semantics, and case ownership explicit. AI coding agents can help maintain those conventions, but they need the conventions in writing.

The third mistake is ignoring operational ownership because the software is open source. Backups, upgrades, SMTP, authentication, TLS certificates, uploaded artifacts, and bug tracker credentials are production responsibilities. If Kiwi TCMS becomes the official release evidence system, treat it like production infrastructure.

Frequently Asked Questions

Is Kiwi TCMS really free to use?

Kiwi TCMS Community Edition is open source and can be run free of charge, but the project also sells subscriptions, hosted/private tenant options, support, Enterprise packaging, and access to versioned or multi-arch container images. The public Community container is a rolling image. If you need pinned vendor images, warranty, or Enterprise add-ons, plan for a paid subscription rather than assuming all production conveniences are free.

Can Kiwi TCMS replace TestRail?

It can replace TestRail for many teams that need plans, cases, runs, execution results, reports, bug links, and automation imports. The decision depends on hosting appetite, migration quality, permissions, reporting expectations, and integrations. Kiwi gives more control and open-source transparency. SaaS tools may offer less operational burden and more polished managed workflows. Run a pilot with real data before committing.

Which automation plugin should a new team start with?

Start with the JUnit XML plugin if your ecosystem already emits JUnit XML because it works across many languages and CI systems. Use the pytest plugin when your Python suite should report directly and you are comfortable with plugin behavior. Use the Robot Framework plugin for Robot suites, especially when you can map tests to existing cases with TC-xyz tags. Pin plugin versions and test imports on staging.

What should AI coding agents read from Kiwi TCMS?

Agents should read well-structured plans, cases, expected results, tags, components, and recent execution failures. That context helps them generate focused Playwright, pytest, API, or integration tests. Do not let agents treat Kiwi TCMS as an unchecked source of truth if the data is stale. Give them current case IDs, product/version rules, and explicit instructions for whether they may create, update, or only read records.