> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cynative.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Contributing to Cynative: Setup, Gates, and PR Flow

> Set up your Cynative development environment, understand the CI gates, write tests, and follow PR conventions for squash-merge linear history.

Cynative is released under the Apache-2.0 license and contributions are welcome. The most impactful areas are new agents, new connectors, evaluation datasets that improve research quality, and fixes across the codebase. Every contribution — code, docs, or data — goes through the same gate.

## Prerequisites

| Tool | Requirement |
| - | - |
| Go toolchain | Version matching `go.mod` (Go 1.27+). |
| `make` and a POSIX shell | Required for all gate targets. |
| CGO | Required for race tests (`-race` needs a C compiler). |
| `shellcheck` | Pinned version set in the `Makefile`; installed separately. |
| PowerShell 7 with Pester and PSScriptAnalyzer | Pinned versions in the `Makefile`; installed separately. Required for `make check-scripts`. |
| Python 3 + PyYAML | `python3-yaml` on apt or `PyYAML` via pip. Used by the llm-smoke secret-boundary checks. |
| `jq` | Used by the Scoop-renderer and release asset-set suites inside `sh-test`. |
| `openssl` | Needed by `test/proxy.smoke.test.sh`, which builds the binary and mints a test CA. |

Go tooling (`golangci-lint`, `moq`, `gocyclo`, `gocognit`, `goreleaser`) is declared in the `tool` block of `go.mod` and invoked through `make` as `go tool <name>` — do not install them separately. Dependabot keeps them up to date.

On a fresh checkout, generate the gitignored mocks before running any package tests:

```bash theme={null}
make generate
```

## Development workflow

```bash theme={null}
make check-go    # Go gate: mod-tidy-check, generate, lint, format, race tests, windows cross-build
make check       # Full gate: check-go + check-scripts (shellcheck, PSScriptAnalyzer, Pester, sh-test)
make generate    # Regenerate mocks and agent catalog — run before go test on a fresh checkout
make test        # Runs the full race-enabled test suite with the coverage gate
make format      # Reformats sources with golangci-lint fmt
```

`make check-go` is what the pre-commit hook runs. `make check` is the full gate every PR must pass. The two halves are:

* **`check-go`** — `mod-tidy-check` + `generate` + `lint` + `shell-complexity` + `format-diff` + the full race-enabled test suite (`-race -shuffle=on`) + `windows-build` (GOOS=windows, amd64 and arm64). 100 % `go.mod`-pinned.
* **`check-scripts`** — `shellcheck` over every tracked `*.sh`, PSScriptAnalyzer over every tracked `*.ps1`, Pester over every tracked `test/*.Tests.ps1`, and `sh-test` (install, connector, render, signing, CI-gate, and llm-smoke suites). Requires `python3`, PyYAML, `jq`, shellcheck, Pester, and PSScriptAnalyzer.

<Note>
  Run `make check-go` before every commit and `make check` before opening a PR. The pre-commit hook wires `make check-go` automatically, but only where `pre-commit install` has been run — a successful `git commit` proves nothing about the gate unless that hook is installed.
</Note>

## Running a single test

```bash theme={null}
go test ./internal/agent -run TestName -count=1 -race
```

Add `-race` to match CI. CGO must be available. Run `make generate` first on a fresh checkout — the moq mock files (`*_mock_test.go`) are gitignored and packages will not compile without them.

## Code conventions

These conventions are enforced by `.golangci.yaml` (golangci-lint v2) and by the gates:

**Formatting and style**

* 120-column line limit (`golines`), `gofumpt` formatting, `goimports` with local prefix `github.com/cynative/cynative`.
* Every comment ends in a period (`godot`).
* No magic numbers (`mnd`).
* Function length limit: 100 lines or 50 statements. Cyclomatic complexity ≤ 30, cognitive complexity ≤ 20.

**Package structure**

* No `init()` and no mutable package globals. `//nolint:gochecknoglobals` is accepted only for immutable lookup tables, stateless singletons, and `// test export` aliases in `export_test.go`.
* Read the process environment only in the composition root and in `*_shell.go` files. `forbidigo` bans `os.Getenv`, `os.LookupEnv`, `os.Environ`, and `t.Setenv` everywhere else. Pass a `lookupEnv` func into constructors and use that in tests.

  ```go theme={null}
  // Wrong inside a core package — forbidigo fails lint:
  key, _ := os.LookupEnv("OPENAI_API_KEY")

  // Right — use the injected lookup func the constructor received:
  key, _ := lookupEnv("OPENAI_API_KEY")
  ```

**Errors**

* Errors wrap with `%w`.
* Sentinel errors are named `ErrX`; error types are named `XError` (`errname` enforces both).

**Ports and adapters**

* Every external dependency (cloud SDKs, OS, filesystem, network, stdio, terminal, the Bifrost client, the sobek runtime) is a constructor-injected interface or function field, defaulted to the real implementation. Tests swap implementations through `With*` options in `export_test.go`, never by reassigning a package variable.

**nolint markers**

* Every `//nolint` must be `//nolint:<linter> // reason`. A bare marker or a missing reason is rejected by `nolintlint` (except for `funlen`, `gocognit`, and `golines`, where the reason may be omitted — write it anyway).

## Coverage and complexity gates

* **Coverage gate:** 100 % statement coverage of all core code (everything except `*_shell.go` files and `internal/auth/authtest`). The gate is exact — add a test for every new branch.
* **Shell complexity gate:** every function in a `*_shell.go` file must have cyclomatic and cognitive complexity ≤ 6. Move branchy logic into covered core files rather than raising the budget. `//gocyclo:ignore` and `//gocognit:ignore` are rejected.
* A core error path that no test can reach (a constructor whose real implementation cannot fail) is handled with a factory field defaulted, branch-free, to a `*_shell.go` function — not with a `//nolint`.

## Adding a new agent

An agent is a markdown file with strict YAML frontmatter (only key: `description`) followed by the prompt body. The filename is the agent name.

1. Create one `.md` file in `agents/`.
2. Run `make generate` to update the embedded agent catalog (`docs/agents-catalog.md`). The `catalog-check` in `make check-go` compares the staged catalog against a fresh render — stage the regenerated catalog alongside your agent file or the gate fails.
3. Never hand-edit `docs/agents-catalog.md`.

## Adding a connector

A new connector needs:

1. **`docs/connectors/<name>.md`** — a guide covering credential discovery, hardening, limitations, and examples. The `connectorDocs` roster in `internal/auth/connector_docs_test.go` must include the new file; a missing entry fails that test.
2. **Test roster entries** — add a row to both `connectorDocs` (`connector_docs_test.go`) and `connectorArgsKeys` (`connector_args_test.go`). If the connector takes per-call arguments, its block in `transport.RequestArgs` is tagged `<name>_auth` and that tag is the row's value; connectors with no block (like `github` and `gitlab`) use an empty value.

## Branch and PR conventions

**Branches**

* Always branch from `main` using the pattern `<type>/<short-description>`.
* Examples: `feat/mcp-support`, `fix/exit-code-no-answer`, `docs/architecture-page`, `ci/release-dispatch-retrigger`.
* Direct pushes to `main` are blocked by a ruleset for everyone except org admins and one GitHub App.

**PR titles**

* PR titles must follow [Conventional Commits](https://www.conventionalcommits.org/) — enforced by CI (`Validate PR title`).
* Allowed types: `build`, `chore`, `ci`, `deps`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`.
* Use `deps:` for dependency-only bumps and `fix:` only for product defects.
* Mark breaking changes with `!` and a `BREAKING CHANGE:` footer.

**Merging**

* PRs are squash-merged with linear history. Keep PRs focused.
* Required checks — `Lint & Test`, `Validate PR title`, and `Build & smoke-test macOS packaging toolchain` — must pass on an up-to-date branch, every review thread must be resolved, and there must be no open CodeQL alerts before merge.
* Rebase onto `main` before requesting a merge; a stale branch cannot merge.

**Changelog**

* Never hand-edit `CHANGELOG.md` or `.release-please-manifest.json`. release-please generates both from the Conventional Commit PR titles automatically.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.