Niteni (Javanese: to observe carefully, to pay close attention)
AI-powered code review for GitLab CI pipelines, powered by the Gemini REST API.
Analyzes code changes via the Gemini API with structured output, then posts severity-classified findings as GitLab MR notes.
Niteni calls the Gemini REST API with structured output (responseSchema + responseMimeType: "application/json") to get typed JSON findings directly — no regex parsing needed. Each finding includes severity, file, line, description, suggestion, and rationale, which Niteni posts as inline comments on the merge request.
- Inline diff comments — Findings are posted directly on the changed lines in the MR diff
- Severity-based emojis — 🚨 CRITICAL,
⚠️ HIGH, 🔵 MEDIUM, ℹ️ LOW - GitLab suggestion blocks — One-click "Apply suggestion" for each code fix
- Rationale explanations — Each suggestion includes why the change is recommended
- Automatic cleanup of previous review comments on re-review
- Configurable file filtering (include/exclude patterns)
- Diff size limits to manage token usage
- Optional pipeline failure on CRITICAL findings
In your GitLab project, go to Settings > CI/CD > Variables and add:
| Variable | Description | Required |
|---|---|---|
GEMINI_API_KEY |
Google Gemini API key | Yes |
GITLAB_TOKEN |
GitLab access token with api scope |
Yes |
niteni-code-review:
stage: review
image: node:20-alpine
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
before_script:
- apk add --no-cache git curl bash
# Clone and build Niteni
- git clone https://github.com/denyherianto/niteni.git /tmp/niteni
- cd /tmp/niteni && npm ci && npm run build && npm link
- cd $CI_PROJECT_DIR
script:
- niteni --mode mr
allow_failure: trueNote: Do NOT re-declare
GEMINI_API_KEYorGITLAB_TOKENin the jobvariables:section — this causes a circular reference. Project-level CI/CD variables are automatically available in all jobs.
All configuration is via environment variables:
| Variable | Default | Description |
|---|---|---|
GEMINI_API_KEY |
- | Gemini API key |
GITLAB_TOKEN |
$CI_JOB_TOKEN |
GitLab access token |
CI_PROJECT_ID |
- | GitLab project ID (auto-set in CI) |
CI_MERGE_REQUEST_IID |
- | MR IID (auto-set in CI) |
GEMINI_MODEL |
gemini-3-pro-preview |
Gemini model for review |
REVIEW_MAX_FILES |
50 |
Max files to review |
REVIEW_MAX_DIFF_SIZE |
100000 |
Max diff size (characters) |
REVIEW_INCLUDE_PATTERNS |
- | File patterns to include (comma-separated) |
REVIEW_EXCLUDE_PATTERNS |
package-lock.json,yarn.lock,*.min.js,*.min.css |
File patterns to exclude |
REVIEW_POST_AS_NOTE |
true |
Post review as MR note |
REVIEW_FAIL_ON_CRITICAL |
false |
Fail pipeline on CRITICAL findings |
Findings are posted as inline diff comments directly on the changed lines. Each comment includes:
- Severity badge with emoji
- Issue description
- Suggestion with rationale explanation
- GitLab "Apply suggestion" button for one-click fixes
- 🚨 CRITICAL — Security vulnerabilities, data loss, logic failures
⚠️ HIGH — Performance bottlenecks, architectural violations, functional bugs- 🔵 MEDIUM — Input validation gaps, error handling issues
- ℹ️ LOW — Documentation, minor readability issues
Issue: Missing token expiration check allows indefinite session reuse.
Suggestion: Adding an expiration check prevents stolen tokens from being used indefinitely.
if (decoded.exp < Date.now() / 1000) { throw new AuthError('Token expired'); }
The package auto-publishes on version tags:
git tag v1.0.0
git push origin v1.0.0The publish-package CI job will publish to your project's NPM registry.
# Configure registry
npm config set registry https://gitlab.com/api/v4/projects/YOUR_PROJECT_ID/packages/npm/
npm config set -- '//gitlab.com/api/v4/projects/YOUR_PROJECT_ID/packages/npm/:_authToken' "YOUR_TOKEN"
# Publish
npm publishniteni/
├── src/
│ ├── types/
│ │ ├── index.ts # Barrel export for all types
│ │ ├── config.ts # AppConfig, GitLabConfig, GeminiConfig, ReviewConfig
│ │ ├── gitlab.ts # MergeRequest, MergeRequestNote, DiffPosition, etc.
│ │ └── reviewer.ts # Severity, Finding, StructuredReviewResponse, ReviewResult
│ ├── index.ts # Main module & orchestration
│ ├── cli.ts # CLI entry point
│ ├── simulate.ts # Simulation mode with mock data
│ ├── reviewer.ts # Gemini structured output review logic
│ ├── gitlab-api.ts # GitLab API client
│ └── config.ts # Configuration values
├── dist/ # Compiled output (generated)
├── scripts/
│ └── ci-review.sh # CI helper script
├── .gitlab-ci.yml # GitLab CI pipeline
├── tsconfig.json # TypeScript configuration
├── .npmrc # NPM registry config
├── package.json
└── README.md
Copy the prompt below into your AI coding tool (Claude Code, Cursor, GitHub Copilot, Windsurf, etc.) to integrate Niteni into your GitLab repository:
Integrate "Niteni" — an AI-powered code review tool — into this GitLab repository. Niteni uses the Gemini REST API with structured output to automatically review merge request diffs and post findings as MR notes.
## Steps
1. Add a `niteni` job to `.gitlab-ci.yml` that runs on merge request events:
niteni-code-review:
stage: review
image: node:20-alpine
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
before_script:
- apk add --no-cache git curl bash
- git clone https://github.com/denyherianto/niteni.git /tmp/niteni
- cd /tmp/niteni && npm ci && npm run build && npm link
- cd $CI_PROJECT_DIR
script:
- niteni --mode mr
allow_failure: true
IMPORTANT: Do NOT re-declare GEMINI_API_KEY or GITLAB_TOKEN in the job `variables:` section.
Project-level CI/CD variables are automatically available in all jobs. Re-declaring them
causes a circular reference where the variable expands to a literal string instead of its value.
2. Ensure the following CI/CD variables are configured in GitLab (Settings > CI/CD > Variables).
Set them as type "Variable" (not "File"), check "Mask variable", and UNCHECK "Protect variable":
- GEMINI_API_KEY — Google Gemini API key
- GITLAB_TOKEN — GitLab Personal Access Token with `api` scope
3. Optional environment variables (these CAN be added to the job `variables:` section since they are plain values, not references):
- GEMINI_MODEL (default: gemini-3-pro-preview) — Gemini model for review
- REVIEW_MAX_FILES (default: 50) — Max files to include in the review
- REVIEW_MAX_DIFF_SIZE (default: 100000) — Max diff size in characters
- REVIEW_INCLUDE_PATTERNS — Comma-separated glob patterns to include (e.g. "src/**,lib/**")
- REVIEW_EXCLUDE_PATTERNS — Comma-separated glob patterns to exclude
- REVIEW_POST_AS_NOTE (default: true) — Post review as MR note
- REVIEW_FAIL_ON_CRITICAL (default: false) — Fail the pipeline when CRITICAL findings are found
4. If the existing `.gitlab-ci.yml` does not have a `review` stage, add it to the `stages` list.
5. Test the integration by opening a merge request. Niteni will automatically review the diff and post a comment with severity-classified findings (CRITICAL, HIGH, MEDIUM, LOW) and suggested code fixes.
MIT