diff --git a/.ci/vale/vale.sh b/.ci/vale/vale.sh index e0f385f58..1ea3b422b 100755 --- a/.ci/vale/vale.sh +++ b/.ci/vale/vale.sh @@ -13,7 +13,7 @@ set -euo pipefail # --minAlertLevel=suggestion \ # --config=content/influxdb/cloud-dedicated/.vale.ini -VALE_VERSION="3.13.1" +VALE_VERSION="3.14.0" VALE_MAJOR_MIN=3 if command -v vale &>/dev/null; then diff --git a/.claude/agents/doc-review-agent.md b/.claude/agents/doc-review-agent.md new file mode 100644 index 000000000..a16adae0d --- /dev/null +++ b/.claude/agents/doc-review-agent.md @@ -0,0 +1,82 @@ +--- +name: doc-review-agent +description: | + Diff-only PR review agent for documentation changes. Reviews Markdown + changes against style guide, frontmatter rules, shortcode syntax, and + documentation standards. Available for local Claude Code review sessions. +model: sonnet +--- + +You are a documentation review agent for the InfluxData docs-v2 repository. +Your job is to review PR diffs for documentation quality issues. You review +Markdown source only — visual/rendered review is handled separately by Copilot. + +## Review Scope + +Check the PR diff for these categories. Reference the linked docs for +detailed rules — do not invent rules that aren't documented. + +### 1. Frontmatter + +Rules: [DOCS-FRONTMATTER.md](../../DOCS-FRONTMATTER.md) + +- `title` and `description` are required on every page +- `menu` structure matches the product's menu key +- `weight` is present and uses the correct range (1-99, 101-199, etc.) +- `source` paths for shared content point to valid `/shared/` paths +- No duplicate or conflicting frontmatter keys + +### 2. Shortcode Syntax + +Rules: [DOCS-SHORTCODES.md](../../DOCS-SHORTCODES.md) + +- Shortcodes use correct opening/closing syntax (`{{< >}}` vs `{{% %}}` + depending on whether inner content is Markdown) +- Required parameters are present +- Closing tags match opening tags +- Callouts use GitHub-style syntax: `> [!Note]`, `> [!Warning]`, etc. + +### 3. Semantic Line Feeds + +Rules: [DOCS-CONTRIBUTING.md](../../DOCS-CONTRIBUTING.md) + +- One sentence per line +- Long sentences should be on their own line, not concatenated + +### 4. Heading Hierarchy + +- No h1 headings in content (h1 comes from `title` frontmatter) +- Headings don't skip levels (h2 → h4 without h3) + +### 5. Terminology and Product Names + +- Use official product names: "InfluxDB 3 Core", "InfluxDB 3 Enterprise", + "InfluxDB Cloud Serverless", "InfluxDB Cloud Dedicated", etc. +- Don't mix v2/v3 terminology in v3 docs (e.g., "bucket" in Core docs) +- Version references match the content path + +### 6. Links + +- Internal links use relative paths or Hugo `relref` shortcodes +- No hardcoded `docs.influxdata.com` links in content files +- Anchor links match actual heading IDs + +### 7. Shared Content + +- `source:` frontmatter points to an existing shared file path +- Shared files don't contain frontmatter (only content) +- Changes to shared content are intentional (affects multiple products) + +## Output Format + +Follow the shared review comment format, severity definitions, and label +mapping in +[.github/templates/review-comment.md](../../.github/templates/review-comment.md). + +## What NOT to Review + +- Rendered HTML appearance (Copilot handles this) +- Code correctness inside code blocks (pytest handles this) +- Link validity (link-checker workflow handles this) +- Vale style linting (Vale handles this) +- Files outside the diff diff --git a/.claude/agents/doc-triage-agent.md b/.claude/agents/doc-triage-agent.md new file mode 100644 index 000000000..59a4b4eff --- /dev/null +++ b/.claude/agents/doc-triage-agent.md @@ -0,0 +1,72 @@ +--- +name: doc-triage-agent +description: | + Triage agent for documentation issues and PRs. Applies product labels, + assesses priority, and determines readiness for automated workflows. + Uses data/products.yml as the single source of truth for path-to-product + mapping. +model: sonnet +--- + +You are a documentation triage agent for the InfluxData docs-v2 repository. +Your job is to label, prioritize, and route issues and PRs for the +documentation team. + +## Label Taxonomy + +Apply labels using the definitions in these source files: + +- **Product labels** (`product:*`): Read + [data/products.yml](../../data/products.yml) — match changed file paths + against each product's `content_path`, apply `product:{label_group}`. + Apply all matching labels. For shared content, apply `product:shared` plus + labels for all products that reference the shared file. +- **Non-product labels**: Read + [data/labels.yml](../../data/labels.yml) for all source, waiting, workflow, + and review label names and descriptions. +- **Review labels** (`review:*`): Defined in `data/labels.yml` but applied + only by the doc-review workflow, not during triage. + +## Priority Assessment + +Assess priority based on: + +1. **Product tier:** InfluxDB 3 Core/Enterprise > Cloud Dedicated/Serverless > v2 > v1 +2. **Issue type:** Incorrect information > missing content > style issues +3. **Scope:** Security/data-loss implications > functional docs > reference docs +4. **Staleness:** Issues with `waiting:*` labels older than 14 days should be + escalated or re-triaged + +## Decision Logic + +### When to apply `agent-ready` + +Apply when ALL of these are true: +- The issue has clear, actionable requirements +- No external dependencies (no `waiting:*` labels) +- The fix is within the documentation scope (not a product bug) +- Product labels are applied (agent needs to know which content to modify) + +### When to apply `waiting:*` + +Apply when the issue: +- References undocumented API behavior → `waiting:engineering` +- Requires a product decision about feature naming or scope → `waiting:product` +- Needs clarification from the reporter about expected behavior → add a comment asking, don't apply waiting + +### When to apply `review:needs-human` + +Apply during triage only if: +- The issue involves complex cross-product implications +- The content change could affect shared content used by many products +- The issue requires domain expertise the agent doesn't have + +## Triage Workflow + +1. Read the issue/PR title and body +2. Identify affected products from content paths or mentions +3. Apply product labels +4. Apply source label if applicable +5. Assess whether the issue is ready for agent work +6. Apply `agent-ready` or `waiting:*` as appropriate +7. Post a brief triage comment summarizing the labeling decision diff --git a/.claude/agents/influxdb1-tech-writer.md b/.claude/agents/influxdb1-tech-writer.md index 2ec900b83..a65681fed 100644 --- a/.claude/agents/influxdb1-tech-writer.md +++ b/.claude/agents/influxdb1-tech-writer.md @@ -61,6 +61,15 @@ You are an expert InfluxDB v1 technical writer with deep knowledge of InfluxData 5. **Apply Standards:** Ensure compliance with style guidelines and documentation conventions 6. **Cross-Reference:** Verify consistency with related documentation and product variants +## Release Documentation Workflow + +**Always create separate PRs for OSS v1 and Enterprise v1 releases.** + +- **OSS v1:** Publish immediately when the release tag is available on GitHub (`https://github.com/influxdata/influxdb/releases/tag/v1.x.x`). +- **Enterprise v1:** Publish only after the release artifact is generally available (GA) in the InfluxData portal. Create the PR as a **draft** until the v1 codeowner signals readiness (e.g., applies a release label). +- **`data/products.yml`:** Split version bumps per product. The OSS PR bumps `influxdb.latest_patches.v1`; the Enterprise PR bumps `enterprise_influxdb.latest_patches.v1`. +- **PR template:** Use `.github/pull_request_template/influxdb_v1_release.md` and select the appropriate release type (OSS or Enterprise). + ## Quality Assurance - All code examples must be testable and include proper pytest-codeblocks annotations diff --git a/.claude/commands/prepare-release-notes.md b/.claude/commands/prepare-release-notes.md index e3e241fd2..c51350493 100644 --- a/.claude/commands/prepare-release-notes.md +++ b/.claude/commands/prepare-release-notes.md @@ -222,6 +222,29 @@ influxdb3_core, influxdb3_enterprise, telegraf /influxdb3/core, /influxdb3/enterprise, /telegraf ``` +## v1 Release Workflow + +**InfluxDB v1 releases require separate PRs for OSS and Enterprise.** + +1. **OSS PR** — publish immediately when the GitHub release tag is available. +2. **Enterprise PR** — create as a draft; merge only after the v1 codeowner signals readiness (e.g., applies a release label) and the release artifact is GA in the InfluxData portal. + +Each PR should bump only its own product version in `data/products.yml`: +- OSS: `influxdb > latest_patches > v1` +- Enterprise: `enterprise_influxdb > latest_patches > v1` + +Use the PR template `.github/pull_request_template/influxdb_v1_release.md` and select the appropriate release type. + +### Examples for v1 + +```bash +# Generate OSS v1 release notes +docs release-notes v1.12.2 v1.12.3 --repos ~/github/influxdata/influxdb + +# Generate Enterprise v1 release notes (separate PR) +# Use the Enterprise changelog at https://dl.influxdata.com/enterprise/nightlies/master/CHANGELOG.md +``` + ## Related - **docs-cli-workflow** skill - When to use CLI tools diff --git a/.claude/settings.json b/.claude/settings.json index f5838526b..c21b0380a 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,51 +1,51 @@ { "permissions": { "allow": [ - "Bash(.ci/vale/vale.sh:*)", - "Bash(npm:*)", - "Bash(yarn:*)", - "Bash(pnpm:*)", - "Bash(npx:*)", - "Bash(node:*)", - "Bash(python:*)", - "Bash(python3:*)", - "Bash(pip:*)", - "Bash(poetry:*)", - "Bash(make:*)", - "Bash(cargo:*)", - "Bash(go:*)", - "Bash(curl:*)", - "Bash(gh:*)", - "Bash(hugo:*)", - "Bash(htmlq:*)", - "Bash(jq:*)", - "Bash(yq:*)", - "Bash(mkdir:*)", - "Bash(cat:*)", - "Bash(ls:*)", - "Bash(echo:*)", - "Bash(rg:*)", - "Bash(grep:*)", - "Bash(find:*)", - "Bash(bash:*)", - "Bash(wc:*)", - "Bash(sort:*)", - "Bash(uniq:*)", - "Bash(head:*)", - "Bash(tail:*)", - "Bash(awk:*)", - "Bash(touch:*)", - "Bash(docker:*)", - "Edit", - "Read", - "Write", - "Grep", - "Glob", - "LS", - "Skill(superpowers:brainstorming)", - "Skill(superpowers:brainstorming:*)", - "mcp__acp__Bash" - ], + "Bash(.ci/vale/vale.sh:*)", + "Bash(npm:*)", + "Bash(yarn:*)", + "Bash(pnpm:*)", + "Bash(npx:*)", + "Bash(node:*)", + "Bash(python:*)", + "Bash(python3:*)", + "Bash(pip:*)", + "Bash(poetry:*)", + "Bash(make:*)", + "Bash(cargo:*)", + "Bash(go:*)", + "Bash(curl:*)", + "Bash(gh:*)", + "Bash(hugo:*)", + "Bash(htmlq:*)", + "Bash(jq:*)", + "Bash(yq:*)", + "Bash(mkdir:*)", + "Bash(cat:*)", + "Bash(ls:*)", + "Bash(echo:*)", + "Bash(rg:*)", + "Bash(grep:*)", + "Bash(find:*)", + "Bash(bash:*)", + "Bash(wc:*)", + "Bash(sort:*)", + "Bash(uniq:*)", + "Bash(head:*)", + "Bash(tail:*)", + "Bash(awk:*)", + "Bash(touch:*)", + "Bash(docker:*)", + "Edit", + "Read", + "Write", + "Grep", + "Glob", + "LS", + "Skill(superpowers:brainstorming)", + "Skill(superpowers:brainstorming:*)", + "mcp__acp__Bash" + ], "deny": [ "Read(./.env)", "Read(./.env.*)", @@ -58,5 +58,8 @@ "Bash(rm:*)", "Read(/tmp)" ] + }, + "enabledPlugins": { + "github@claude-plugins-official": true } } diff --git a/.claude/skills/content-editing/SKILL.md b/.claude/skills/content-editing/SKILL.md index eb35f23e6..d34b1bd6b 100644 --- a/.claude/skills/content-editing/SKILL.md +++ b/.claude/skills/content-editing/SKILL.md @@ -359,33 +359,12 @@ Use the Documentation MCP Server when the information here is inconclusive, when ### Setup -The documentation MCP server is hosted—no local installation required. Add the server URL to your AI assistant's MCP configuration. +The documentation MCP server is hosted at `https://influxdb-docs.mcp.kapa.ai`—no local installation required. -**MCP server URL:** +Already configured in [`.mcp.json`](/.mcp.json). Two server entries are available: -```text -https://influxdb-docs.mcp.kapa.ai -``` - -**Claude Desktop configuration** (Settings > Developer): - -```json -{ - "mcpServers": { - "influxdb-docs": { - "url": "https://influxdb-docs.mcp.kapa.ai" - } - } -} -``` - -For other AI assistants see the [InfluxDB documentation MCP server guide](/influxdb3/core/admin/mcp-server/) -and verify the MCP configuration options and syntax for a specific AI assistant. - -**Rate limits** (per Google OAuth user): - -- 40 requests per hour -- 200 requests per day +- **`influxdb-docs`** (API key) — Set `INFLUXDATA_DOCS_KAPA_API_KEY` env var. 60 req/min. +- **`influxdb-docs-oauth`** (OAuth) — No setup. Authenticates via Google or GitHub on first use. 40 req/hr, 200 req/day. ### Available Tool @@ -552,17 +531,12 @@ touch content/influxdb3/enterprise/path/to/file.md ### MCP Server Not Responding -The hosted MCP server (`https://influxdb-docs.mcp.kapa.ai`) requires: - -1. **Google OAuth authentication** - On first use, sign in with Google -2. **Rate limits** - 40 requests/hour, 200 requests/day per user - **Troubleshooting steps:** -- Verify your AI assistant has the MCP server URL configured correctly -- Check if you've exceeded rate limits (wait an hour or until the next day) -- Try re-authenticating by clearing your OAuth session -- Ensure your network allows connections to `*.kapa.ai` +- **API key auth** (`influxdb-docs`): Verify `INFLUXDATA_DOCS_KAPA_API_KEY` is set. Rate limit: 60 req/min. +- **OAuth auth** (`influxdb-docs-oauth`): Sign in with Google or GitHub on first use. Rate limits: 40 req/hr, 200 req/day. +- Verify your network allows connections to `*.kapa.ai` +- Check if you've exceeded rate limits (wait and retry) ### Cypress Tests Fail diff --git a/.claude/skills/vale-linting/SKILL.md b/.claude/skills/vale-linting/SKILL.md index aa324981c..760487d52 100644 --- a/.claude/skills/vale-linting/SKILL.md +++ b/.claude/skills/vale-linting/SKILL.md @@ -299,15 +299,42 @@ echo "systemd" >> .ci/vale/styles/config/vocabularies/InfluxDataDocs/accept.txt ### Creating a Product-Specific Override +> [!Important] +> Product-specific `.vale.ini` files must include the same disabled rules as the +> root `.vale.ini`. Rules disabled in the root config are **not** inherited by +> product-specific configs. Omitting them re-enables the rules for those products. +> For example, omitting `Google.Units = NO` causes duration literals like `7d`, +> `24h` to be flagged as errors in product-specific linting runs. + ```bash # 1. Create product-specific .vale.ini cat > content/influxdb3/cloud-dedicated/.vale.ini << 'EOF' StylesPath = ../../../.ci/vale/styles -MinAlertLevel = error +MinAlertLevel = warning Vocab = InfluxDataDocs +Packages = Google, write-good, Hugo + [*.md] BasedOnStyles = Vale, InfluxDataDocs, Google, write-good + +# These rules must be disabled in every product .vale.ini, same as the root .vale.ini. +Google.Acronyms = NO +Google.DateFormat = NO +Google.Ellipses = NO +Google.Headings = NO +Google.WordList = NO +# Disable Google.Units in favor of InfluxDataDocs.Units which only checks byte +# units (GB, TB, etc). Duration literals (30d, 24h, 1h) are valid InfluxDB syntax. +Google.Units = NO +Vale.Spelling = NO +Vale.Terms = NO +write-good.TooWordy = NO + +TokenIgnores = /[a-zA-Z0-9/_\-\.]+, \ + https?://[^\s\)\]>"]+, \ + `[^`]+` + # Product-specific overrides InfluxDataDocs.Branding = YES EOF diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..c1965c216 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.github/workflows/*.lock.yml linguist-generated=true merge=ours \ No newline at end of file diff --git a/.github/DOC-REVIEW-PIPELINE-PLAN.md b/.github/DOC-REVIEW-PIPELINE-PLAN.md new file mode 100644 index 000000000..60815f485 --- /dev/null +++ b/.github/DOC-REVIEW-PIPELINE-PLAN.md @@ -0,0 +1,704 @@ +# Doc Review Pipeline — Implementation Plan + +**Status:** Complete — all phases implemented and tested +**Repository:** influxdata/docs-v2 +**Author:** Triage agent (Claude Code) +**Date:** 2026-02-28 + +--- + +## Table of Contents + +1. [Goal](#goal) +2. [What Already Exists](#what-already-exists) +3. [Architecture Overview](#architecture-overview) +4. [Phase 1: Label System Overhaul](#phase-1-label-system-overhaul) +5. [Phase 2: Doc Review Workflow](#phase-2-doc-review-workflow) +6. [Phase 3: Documentation and Agent Instructions](#phase-3-documentation-and-agent-instructions) +7. [Future Phases (Not In Scope)](#future-phases-not-in-scope) +8. [Decisions (Resolved)](#decisions-resolved) +9. [Risk Assessment](#risk-assessment) + +--- + +## Goal + +Build two interconnected systems: + +1. **Label system** — An automation-driven label taxonomy that supports + cross-repo automation, agentic workflows, and human-in-the-loop review. +2. **Doc review pipeline** — A GitHub Actions workflow that automates + documentation PR review using Copilot for both code review (diff-based, + using auto-loaded instruction files) and visual review (rendered HTML + at preview URLs), with rendered-page verification that catches issues + invisible in the Markdown source. + +The pipeline catches issues only visible in rendered output — expanded +shortcodes, broken layouts, incorrect product names — by having Copilot +analyze the rendered HTML of deployed preview pages. + +--- + +## What Already Exists + +### Infrastructure + +| Component | Location | Notes | +|-----------|----------|-------| +| PR preview deployment | `.github/workflows/pr-preview.yml` | Builds Hugo site, deploys to `gh-pages` branch at `influxdata.github.io/docs-v2/pr-preview/pr-{N}/` | +| Changed file detection | `.github/scripts/detect-preview-pages.js` | Detects changed files, maps content to public URLs, handles shared content | +| Content-to-URL mapping | `scripts/lib/content-utils.js` | `getChangedContentFiles()`, `mapContentToPublic()`, `expandSharedContentChanges()` | +| Screenshot tooling | `scripts/puppeteer/screenshot.js` | Puppeteer-based screenshot utility (already a dependency) | +| Playwright | `package.json` | Already a dependency (`^1.58.1`) | +| Claude agent instructions | `CLAUDE.md`, `AGENTS.md`, `.claude/` | Review criteria, style guide, skills, commands | +| Copilot instructions | `.github/copilot-instructions.md` | Style guide, repo structure, patterns | +| Copilot pattern instructions | `.github/instructions/` | Auto-loaded by Copilot based on changed file patterns | +| Auto-labeling (path-based) | Not yet implemented | Needed for Phase 1 | +| Link checker workflow | `.github/workflows/pr-link-check.yml` | Validates links on PR changes | +| Sync plugins workflow | `.github/workflows/sync-plugins.yml` | Issue-triggered workflow pattern to follow | +| Audit documentation workflow | `.github/workflows/audit-documentation.yml` | Creates issues from audit results | + +### Labels (Current State) + +The repo has 30+ labels with inconsistent naming patterns and significant +overlap. Product labels use long names (`InfluxDB 3 Core and Enterprise`), +workflow states are minimal (`release:pending` is the only actively used one), +and there is no agent-readiness or blocking-state taxonomy. + +--- + +## Architecture Overview + +``` +PR opened/updated (content paths) + │ + ├──────────────────────────┐ + ▼ ▼ +┌─ Job 1: Resolve URLs ────┐ ┌─ Job 2: Copilot Code Review ───┐ +│ resolve-review-urls.js │ │ gh pr edit --add-reviewer │ +│ changed files → URLs │ │ copilot-reviews │ +│ Output: url list │ │ Uses .github/instructions/ │ +└──────────┬───────────────┘ │ for auto-loaded review rules │ + │ └──────────────┬─────────────────┘ + ▼ │ +┌─ Job 3: Copilot Visual Review ────────┐ │ +│ Wait for preview deployment │ │ +│ Post preview URLs + review prompt │ │ +│ @copilot analyzes rendered HTML │ │ +│ Checks: layout, shortcodes, 404s │ │ +└──────────────┬───────────────────────┘ │ + │ │ + ▼ ▼ + Human reviews what remains +``` + +**Job 2 (Copilot code review) runs in parallel with Jobs 1→3** — it uses +GitHub's native Copilot reviewer, which analyzes the PR diff using +auto-loaded instruction files from `.github/instructions/`. + +--- + +## Phase 1: Label System Overhaul + +### Rationale + +The label system is a prerequisite for agentic workflows. Agents need clear +signals about issue readiness (`agent-ready`), blocking states +(`waiting:engineering`, `waiting:product`), and product scope +(`product:v3-monolith`, `product:v3-distributed`). +Consistent label patterns also enable GitHub API queries for dashboards and +automation. + +### 1.1 — Label taxonomy + +> **Note:** The tables below are a planning snapshot. The authoritative +> definitions live in `data/labels.yml` (non-product labels) and +> `data/products.yml` (product labels). See `.github/LABEL_GUIDE.md` for +> the current index. + +**24 labels organized into 6 categories:** + +#### Product labels (11) — Color: `#FFA500` (yellow) + +| Label | Description | +|-------|-------------| +| `product:v3-monolith` | InfluxDB 3 Core and Enterprise (single-node / clusterable) | +| `product:v3-distributed` | InfluxDB 3 Cloud Serverless, Cloud Dedicated, Clustered | +| `product:v2` | InfluxDB v2 (Cloud, OSS) | +| `product:v1` | InfluxDB v1 OSS | +| `product:v1-enterprise` | InfluxDB Enterprise v1 | +| `product:telegraf` | Telegraf documentation | +| `product:chronograf` | Chronograf documentation | +| `product:kapacitor` | Kapacitor documentation | +| `product:flux` | Flux language documentation | +| `product:explorer` | InfluxDB 3 Explorer | +| `product:shared` | Shared content across products | + +#### Source tracking labels (4) — Color: `#9370DB` (purple) + +| Label | Description | +|-------|-------------| +| `source:auto-detected` | Created by change detection within this repo | +| `source:dar` | Generated by DAR pipeline (issue analysis → draft) | +| `source:sync` | Synced from an external repository | +| `source:manual` | Human-created issue | + +#### Waiting states (2) — Color: `#FF8C00` (orange) + +| Label | Description | +|-------|-------------| +| `waiting:engineering` | Waiting for engineer confirmation | +| `waiting:product` | Waiting for product/PM decision | + +#### Workflow states (2) — Color: `#00FF00` / `#1E90FF` + +| Label | Description | +|-------|-------------| +| `agent-ready` | Agent can work on this autonomously | +| `skip-review` | Skip automated doc review pipeline | + +> [!Note] +> Human codeowner approval uses GitHub's native PR review mechanism (CODEOWNERS file), not a label. The `review:*` labels below are applied **manually** after reviewing Copilot feedback. + +#### Review outcome labels (3) — Color: `#28A745` / `#DC3545` / `#FFC107` + +| Label | Description | +|-------|-------------| +| `review:approved` | Review passed — no blocking issues found | +| `review:changes-requested` | Review found blocking issues | +| `review:needs-human` | Review inconclusive, needs human | + +> [!Note] +> All labels use colons (`:`) as separators for consistency. The `review:*` labels +> are mutually exclusive. They are applied manually after review — the CI workflow +> does not manage labels. Copilot code review uses GitHub's native "Comment" +> review type. + +#### Existing labels to keep (renamed) (2) + +| Old Name | New Name | Description | +|----------|----------|-------------| +| `AI assistant tooling` | `ai:tooling` | Related to AI assistant infrastructure | +| `ci:testing-and-validation` | `ci:testing` | CI/testing infrastructure | + +### 1.2 — Migration scripts + +Create migration scripts in `helper-scripts/label-migration/`: + +- **`create-labels.sh`** — Creates all new labels using `gh label create --force` (idempotent) +- **`migrate-labels.sh`** — Migrates existing issues from old labels to new labels using `gh issue edit` +- **`delete-labels.sh`** — Deletes old labels (requires interactive confirmation) +- **`README.md`** — Execution order, prerequisites, rollback instructions + +**Migration mapping:** + +| Old Label | New Label | +|-----------|-----------| +| `InfluxDB 3 Core and Enterprise` | `product:v3-monolith` | +| `InfluxDB v3` | `product:v3-monolith` (review individually — some may be distributed) | +| `Processing engine` | `product:v3-monolith` | +| `InfluxDB v2` | `product:v2` | +| `InfluxDB v1` | `product:v1` | +| `Enterprise 1.x` | `product:v1-enterprise` | +| `Chronograf 1.x` | `product:chronograf` | +| `Kapacitor` | `product:kapacitor` | +| `Flux` | `product:flux` | +| `InfluxDB 3 Explorer` | `product:explorer` | +| `Pending Release` | `release:pending` | +| `release/influxdb3` | `release:pending` | +| `sync-plugin-docs` | `source:sync` | + +> [!Important] +> **Workflow Updates Required:** +> The `sync-plugin-docs` label is used in GitHub Actions workflows. After migrating this label to `source:sync`, the following files must be updated: +> - `.github/workflows/sync-plugins.yml` (lines 28, 173, 421) +> - `.github/ISSUE_TEMPLATE/sync-plugin-docs.yml` (line 4) +> +> Update all references from `sync-plugin-docs` to `source:sync` to ensure the plugin sync automation continues to work after the label migration. + +> [!Note] +> `release:pending` is an existing workflow state label that we are keeping as-is. +> The migration scripts **must ensure** this label exists (create it if missing) and **must not** delete it in the cleanup step. + +**Labels to delete after migration:** +`bug`, `priority`, `documentation`, `Proposal`, `Research Phase`, +`ready-for-collaboration`, `ui`, `javascript`, `dependencies`, +`integration-demo-blog`, `API`, `Docker`, `Grafana`, `Ask AI`, +plus all old product labels listed above. + +**Execution:** +1. Run `create-labels.sh` (safe, idempotent) +2. Run `migrate-labels.sh` +3. Human verifies a sample of issues +4. Run `delete-labels.sh` (destructive, requires confirmation) + +### 1.3 — Auto-labeling workflow + +**File:** `.github/workflows/auto-label.yml` + +**Trigger:** `pull_request: [opened, synchronize]` + +**Logic:** +- List changed files via `github.rest.pulls.listFiles()` +- Read `data/products.yml` for path-to-label mappings (single source of truth): + - Each product entry has `content_path` and `label_group` fields + - Match file paths against `content/{content_path}/` → `product:{label_group}` + - Example: `content/influxdb3/core/` matches `content_path: influxdb3/core`, + `label_group: v3-monolith` → applies `product:v3-monolith` +- Shared content handling: + - `content/shared/` changes apply `product:shared` label + - Additionally expand shared content to affected products using + `expandSharedContentChanges()` from `scripts/lib/content-utils.js` + - Apply all affected product labels (additive) +- Multi-product PRs: apply all matching `product:*` labels (additive) +- Only add labels that are not already present (idempotent) +- Runs as `actions/github-script@v7` + +--- + +## Phase 2: Doc Review Workflow + +### 2.1 — Workflow file + +**File:** `.github/workflows/doc-review.yml` + +**Trigger:** + +```yaml +on: + pull_request: + types: [opened, synchronize, ready_for_review] + paths: + - 'content/**' + - 'layouts/**' + - 'assets/**' + - 'data/**' +``` + +**Permissions:** `contents: read`, `pull-requests: write` + +**Concurrency:** `group: doc-review-${{ github.event.number }}`, `cancel-in-progress: true` + +**Skip conditions:** Draft PRs, fork PRs, PRs with a `skip-review` label (new label to be added in Phase 1 via the label migration scripts). + +### 2.2 — Job 1: Resolve URLs + +**Purpose:** Map changed files to preview URLs. + +**Implementation:** +- Reuse the existing `detect-preview-pages.js` script and `content-utils.js` library +- Same logic as `pr-preview.yml` Job 1, but output a JSON artifact instead of deploying +- Output format: `[{"file": "content/influxdb3/core/write-data/_index.md", "url": "/influxdb3/core/write-data/"}]` +- Upload as `urls.json` workflow artifact + +**Key detail:** This job runs `getChangedContentFiles()` and `mapContentToPublic()` +from `scripts/lib/content-utils.js`, which already handles shared content +expansion (if `content/shared/foo.md` changes, all pages with +`source: /shared/foo.md` are included). + +### 2.3 — Job 2: Copilot Code Review + +**Purpose:** Review Markdown changes against the style guide and documentation +standards using GitHub's native Copilot code review. Visual review of rendered +pages is handled separately in Job 3. + +**Dependencies:** None beyond the PR itself. This job runs in parallel with +Jobs 1→3. + +**Implementation:** +- Adds `copilot-reviews` as a PR reviewer via `gh pr edit --add-reviewer` +- Copilot automatically reviews the PR diff using instruction files from + `.github/instructions/` that are auto-loaded based on changed file patterns +- No custom prompt or API key required + +**Review criteria file:** `.github/instructions/content-review.instructions.md` + +This file is auto-loaded by Copilot for PRs that change `content/**/*.md` +files. It checks for: + +1. **Frontmatter correctness** — Required fields, menu structure, weights +2. **Shortcode syntax** — Correct usage, closing tags, parameters +3. **Semantic line feeds** — One sentence per line +4. **Heading hierarchy** — No h1 in content (title comes from frontmatter) +5. **Product-specific terminology** — Correct product names, versions +6. **Link format** — Relative links, proper shortcode links +7. **Shared content** — `source:` frontmatter correctness +8. **Code blocks** — Language identifiers, line length, long CLI options + +**Severity classification:** +- `BLOCKING` — Wrong product names, invalid frontmatter, broken shortcode syntax +- `WARNING` — Style inconsistencies, missing semantic line feeds +- `INFO` — Suggestions, not problems + +**Output:** +- Copilot posts inline review comments using GitHub's native "Comment" + review type +- `review:*` labels are applied manually by humans after reviewing the + Copilot feedback — the workflow does not manage labels + +### 2.4 — Job 3: Copilot Visual Review (rendered HTML) + +**Purpose:** Have Copilot analyze the rendered preview pages to catch visual +and structural issues invisible in the Markdown source. + +**Dependencies:** Depends on Job 1 (needs URL list). Must wait for the +`pr-preview.yml` deployment to be live. + +**Why Copilot for visual review:** +- Copilot can analyze rendered HTML content at public preview URLs — no + screenshot capture or image upload required. +- Visual review is a good fit for Copilot because the rendered pages are + self-contained artifacts (no need to cross-reference repo files). +- Copilot code review (Job 2) handles the diff; visual review catches what + the diff review cannot. + +**Implementation:** + +1. **Wait for preview deployment:** + - Poll `https://influxdata.github.io/docs-v2/pr-preview/pr-{N}/` with + `curl --head` until it returns 200 + - Timeout: 10 minutes (preview build takes ~75s + deploy time) + - Poll interval: 15 seconds + - If timeout, skip visual review; Copilot code review (Job 2) still runs + +2. **Post preview URLs and trigger Copilot review:** + - Use `actions/github-script@v7` to post a PR comment listing the preview + URLs from Job 1, formatted as clickable links + - Post a follow-up comment tagging `@copilot` with instructions to review + the rendered pages at the preview URLs. The comment should instruct + Copilot to check each page for: + - Raw shortcode syntax visible on the page (`{{<` or `{{%`) + - Placeholder text that should have been replaced + - Broken layouts: overlapping text, missing images, collapsed sections + - Code blocks rendered incorrectly (raw HTML/Markdown fences visible) + - Navigation/sidebar entries correct + - Visible 404 or error state + - Product name inconsistencies in the rendered page header/breadcrumbs + - The review instruction template is stored in + `.github/prompts/copilot-visual-review.md` for maintainability + - Preview URL count capped at 50 pages (matching `MAX_PAGES` in + `detect-preview-pages.js`) + +3. **Comment upsert pattern:** + - Visual review comments use a marker-based upsert pattern — the workflow + updates an existing comment if one with the marker exists, otherwise + creates a new one. This prevents duplicate comments on `synchronize` + events. + +### 2.6 — Workflow failure handling + +- If preview deployment times out: skip Copilot visual review (Job 3), + Copilot code review (Job 2) still runs independently. Post a comment + explaining visual review was skipped. +- If Copilot does not respond to the `@copilot` mention: the preview URLs + remain in the comment for human review. +- Never block PR merge on workflow failures — the workflow adds comments + but does not set required status checks or manage labels. + +--- + +## Phase 3: Documentation and Agent Instructions + +### 3.1 — Instruction file architecture + +**Principle:** One `CLAUDE.md` that references role-specific files. No per-role +CLAUDE files — Claude Code only reads one `CLAUDE.md` per directory level. The +role context comes from the task prompt (GitHub Actions workflow), not the config +file. + +``` +CLAUDE.md ← lightweight pointer (already exists) + ├── references .github/LABEL_GUIDE.md ← label taxonomy + usage + ├── references .claude/agents/ ← role-specific agent instructions + │ ├── doc-triage-agent.md ← triage + auto-label logic + │ └── doc-review-agent.md ← local review sessions (Claude Code) + └── references .github/instructions/ ← Copilot auto-loaded instructions + └── content-review.instructions.md ← review criteria for content/**/*.md +``` + +**How review roles are assigned at runtime:** +- **Copilot code review (CI):** GitHub's native reviewer. Auto-loads + instruction files from `.github/instructions/` based on changed file + patterns. No custom prompt or API key needed. +- **Copilot visual review (CI):** Triggered by `@copilot` mention in a PR + comment with preview URLs and a review template. +- **Claude local review:** Uses `.claude/agents/doc-review-agent.md` for + local Claude Code sessions. Not used in CI. +- Shared rules (style guide, frontmatter, shortcodes) stay in the existing + referenced files (`DOCS-CONTRIBUTING.md`, `DOCS-SHORTCODES.md`, etc.) +- No duplication — each instruction file says what's unique to that context + +### 3.2 — Agent instruction files + +#### `.claude/agents/doc-triage-agent.md` + +Role-specific instructions for issue/PR triage. Contents: + +- **Label taxonomy** — Full label list with categories, colors, descriptions +- **Path-to-product mapping** — Which content paths map to which `product:*` labels +- **Priority rules** — How to assess priority based on product, scope, and issue type +- **Decision logic** — When to apply `agent-ready`, `waiting:*`, `review:needs-human` +- **Migration context** — Old label → new label mapping (useful during transition) + +This file does NOT duplicate style guide rules. It references +`DOCS-CONTRIBUTING.md` for those. + +#### `.claude/agents/doc-review-agent.md` + +Role-specific instructions for **local** Claude Code review sessions. This +file is NOT used in CI — the CI review is handled by Copilot using +`.github/instructions/content-review.instructions.md`. + +Contents: + +- **Review scope** — Markdown diff review only (frontmatter, shortcodes, + semantic line feeds, heading hierarchy, terminology, links, shared content). +- **Severity classification** — BLOCKING / WARNING / INFO definitions with examples +- **Output format** — Structured review comment template + +This file references `DOCS-CONTRIBUTING.md` for style rules and +`DOCS-SHORTCODES.md` for shortcode syntax — it does NOT restate them. + +### 3.3 — Label usage guide + +**File:** `.github/LABEL_GUIDE.md` + +Contents: +- Label categories with descriptions and colors +- Common workflows (issue triage, DAR pipeline, manual work) +- GitHub filter queries for agents and humans +- Auto-labeling behavior reference + +### 3.4 — Update existing pointer files + +**`CLAUDE.md`** — Add one line to the "Full instruction resources" list: +```markdown +- [.github/LABEL_GUIDE.md](.github/LABEL_GUIDE.md) - Label taxonomy and pipeline usage +``` + +**`AGENTS.md`** — Add a section referencing the label guide and agent roles: +```markdown +## Doc Review Pipeline +- Label guide: `.github/LABEL_GUIDE.md` +- Triage agent: `.claude/agents/doc-triage-agent.md` +- Review agent: `.claude/agents/doc-review-agent.md` +``` + +**`.github/copilot-instructions.md`** — Add the label guide to the +"Specialized Resources" table. + +These are small additions — no restructuring of existing files. + +### 3.5 — Review instruction files + +#### `.github/instructions/content-review.instructions.md` (Copilot code review) + +Auto-loaded by Copilot for PRs that change `content/**/*.md` files. Contains +the review criteria (frontmatter, shortcodes, heading hierarchy, terminology, +links, code blocks) with severity classification. + +This file replaces the original `.github/prompts/doc-review.md` Claude prompt. +The review criteria are the same but delivered through Copilot's native +instruction file mechanism instead of a custom action. + +#### `.github/templates/review-comment.md` (shared format) + +Shared definitions for severity levels, comment structure, and result → label +mapping. Used by `doc-review-agent.md` (local review sessions) and the +Copilot visual review template. + +#### Copilot visual review template + +The `@copilot` visual review comment is constructed inline in the +`doc-review.yml` workflow using the review template from +`.github/templates/review-comment.md`. Contains: + +- The visual review checklist (raw shortcodes, broken layouts, 404s, etc.) +- Instructions for analyzing the rendered pages at the preview URLs +- Output format guidance (what to flag, severity levels) + +--- + +## Future Phases (Not In Scope) + +These are explicitly **not** part of this plan. Documented here for context. + +### v2 — Screenshot-based visual review +- Add Playwright screenshot capture script (`.github/scripts/capture-screenshots.js`) + for design/layout PRs where HTML analysis isn't sufficient. +- Capture full-page PNGs of preview pages, upload as workflow artifacts. +- Useful for PRs touching `layouts/`, `assets/css/`, or template changes + where visual regression matters. +- The existing `scripts/puppeteer/screenshot.js` remains for local debugging; + the CI script should use Playwright for reliability. + +### v3 — Stale PR management +- Cron job that scans for stale PRs (draft >3 days with no review activity) + and pings the author. +- Metrics tracking: % of PRs that pass Copilot review on first attempt. + +### v4 — Agent-driven issue resolution +- Auto-assign doc issues to agents based on `agent-ready` label. +- Claude or Copilot drafts the fix, then the other agent reviews. +- Closes the loop: issue → draft → review → human approval. + +--- + +## Decisions (Resolved) + +### Q1: How should Copilot review rendered pages? — RESOLVED + +**Decision:** Copilot reviews rendered HTML at public preview URLs — no +screenshots needed. Job 3 posts preview URLs in a PR comment, then tags +`@copilot` with a review prompt. See section 2.5 for implementation details. + +This approach works because: +- Preview pages are publicly accessible at `influxdata.github.io/docs-v2/pr-preview/pr-{N}/` +- Copilot can analyze HTML content at public URLs +- No screenshot capture, image upload, or artifact management required + +Screenshot capture is deferred to Future Phases (v2) for design/layout PRs +where visual regression testing matters. + +### Q2: Should the review workflow be a required status check? — RESOLVED + +**Decision:** No. Start as advisory (comments only). The workflow posts review +comments but does not set required status checks or manage labels. `review:*` +labels are applied manually after review. Make it required only after the team +confirms the false-positive rate is acceptable (see Future Phases). + +### Q3: Should screenshots use Playwright or Puppeteer? — DEFERRED + +**Decision:** Deferred to Future Phases (v2). The current implementation +reviews rendered HTML at preview URLs, not screenshots. When screenshot +capture is added later, use Playwright for CI and keep Puppeteer for local +debugging. + +### Q4: How to handle the `pr-preview.yml` dependency? — RESOLVED + +**Decision:** Option A — poll the preview URL with timeout. Job 3 polls +`https://influxdata.github.io/docs-v2/pr-preview/pr-{N}/` with `curl --head` +every 15 seconds until it returns 200, with a 10-minute timeout. If timeout is +reached, skip Copilot visual review; Copilot code review (Job 2) still runs +independently. + +Rationale: Polling is simple, self-contained, and resilient. The URL pattern is +deterministic. Option B (`workflow_run`) adds complexity and doesn't handle +cases where preview doesn't deploy. Option C (combined workflow) makes the +workflow too large and eliminates the parallelism benefit. + +### Q5: Cost and rate limiting — RESOLVED + +**Decision:** Acceptable. Both code review and visual review use the repo's +Copilot allocation. No external API keys or per-call costs. + +Mitigations already designed into the workflow: +- `paths` filter ensures only doc-content PRs trigger the workflow. +- `skip-review` label allows trivial PRs to opt out. +- Concurrency group cancels in-progress reviews when the PR is updated. +- Preview URL count is capped at 50 pages (matching `MAX_PAGES` in + `resolve-review-urls.js`). +- Draft and fork PRs are skipped entirely. + +### Q6: Label separator convention — RESOLVED + +**Decision:** Use colons (`:`) everywhere. No slashes. One separator for +consistency — expecting humans or agents to infer different semantics from +separator choice is unrealistic. Mutually exclusive behavior (e.g., `review:*` +labels) is enforced in workflow code, not punctuation. + +### Q7: Human approval mechanism — RESOLVED + +**Decision:** Use GitHub's native PR review system (CODEOWNERS file) for human +approval. No `approval:codeowner` label. The `review:*` labels are exclusively +for automated pipeline outcomes. + +### Q8: Product path mapping — RESOLVED + +**Decision:** Extend `data/products.yml` with `content_path` and `label_group` +fields. This file becomes the single source of truth for path-to-product +resolution, used by the auto-label workflow, matrix-generator, and documentation +(AGENTS.md). Eliminates duplicated mappings across multiple files. + +### Q9: `sync-plugin-docs` label migration — RESOLVED + +**Decision:** Migrate to `source:sync` (not `source:auto-detected`). Plugin +sync is a distinct operation from change detection. `source:sync` is general +enough to cover future external repo syncs without being hyper-specific. + +### Q10: Multi-product and shared content labeling — RESOLVED + +**Decision:** Auto-labeling is additive — apply all matching `product:*` labels. +Changes to `content/shared/` get the `product:shared` label plus all expanded +product labels (resolved via `expandSharedContentChanges()`). + +--- + +## Risk Assessment + +| Risk | Impact | Mitigation | +|------|--------|------------| +| Preview not deployed in time | Low | 10-minute polling timeout, fall back to code-only review | +| False positives in review | Medium | Start as advisory (not required check), iterate instruction files | +| Label migration data loss | Low | Migrate before deleting; human verification gate | +| Copilot visual review misses issues | Medium | Preview URLs remain in comment for human review; start advisory | +| Copilot code review quality | Medium | Review criteria in `.github/instructions/` can be iterated; local Claude review available as backup | +| Product mapping drift | Low | Single source of truth in `data/products.yml`; auto-label and matrix-generator both derive from it | + +--- + +## File Summary + +Files to create or modify: + +| Action | File | Phase | Status | +|--------|------|-------|--------| +| Modify | `data/products.yml` | 1.0 | Done | +| Modify | `data/labels.yml` | 1.1 | Done | +| Create | `helper-scripts/label-migration/create-labels.sh` | 1.2 | Done | +| Create | `helper-scripts/label-migration/migrate-labels.sh` | 1.2 | Done | +| Create | `helper-scripts/label-migration/delete-labels.sh` | 1.2 | Done | +| Create | `helper-scripts/label-migration/README.md` | 1.2 | Done | +| Create | `.github/workflows/auto-label.yml` | 1.3 | Done | +| Create | `.github/workflows/doc-review.yml` | 2.1 | Done | +| Create | `.claude/agents/doc-triage-agent.md` | 3.2 | Done | +| Create | `.claude/agents/doc-review-agent.md` | 3.2 | Done | +| Create | `.github/LABEL_GUIDE.md` | 3.3 | Done | +| Create | `.github/instructions/content-review.instructions.md` | 3.5 | Done | +| Create | `.github/templates/review-comment.md` | 2.5/3.5 | Done | +| Modify | `CLAUDE.md` | 3.4 | Done | +| Modify | `AGENTS.md` | 3.4 | Done | +| Modify | `.github/copilot-instructions.md` | 3.4 | Done | + +--- + +## Implementation Order + +1. ~~**Phase 1.0** — Extend `data/products.yml` with `content_path` and `label_group`~~ ✅ +2. ~~**Phase 1.1–1.2** — Create label migration scripts~~ ✅ +3. ~~**Phase 1.3** — Create auto-label workflow~~ ✅ +4. ~~**Execute label migration** — Run scripts, then manual cleanup~~ ✅ +5. ~~**Phase 3.2** — Create agent instruction files~~ ✅ +6. ~~**Phase 2.1–2.3** — Workflow skeleton + URL resolution + Copilot code review~~ ✅ +7. ~~**Phase 2.5** — Copilot visual review job~~ ✅ +8. ~~**Phase 3.3–3.5** — Label guide, instruction files, pointer updates~~ ✅ +9. ~~**Test end-to-end** — Triggered workflows via `workflow_dispatch` against PR #6890~~ ✅ + +### End-to-end test results (2026-03-09) + +Triggered via `workflow_dispatch` with `pr_number=6890` on branch +`claude/triage-agent-plan-EOY0u`. + +| Workflow | Job | Result | Notes | +|----------|-----|--------|-------| +| Auto-label PRs | auto-label | Pass | Loaded 14 path mappings, 0 product labels (correct — no content changes) | +| Doc Review | resolve-urls | Pass | 0 preview URLs (correct — no content changes) | +| Doc Review | copilot-review | Pass | `copilot-reviews` added as reviewer | +| Doc Review | copilot-visual-review | Skipped | Correct — 0 URLs to review | + +**Fixes applied during testing:** +- `npm ci` replaced with targeted `js-yaml` install (sparse checkout lacks lock file) +- Added `workflow_dispatch` with `pr_number` input for on-demand re-runs + +**Remaining:** Visual review (Job 3) needs a content-changing PR to fully exercise +the preview URL polling and Copilot `@copilot` mention flow. diff --git a/.github/ISSUE_TEMPLATE/sync-plugin-docs.yml b/.github/ISSUE_TEMPLATE/sync-plugin-docs.yml index 382af5ce3..0331a501c 100644 --- a/.github/ISSUE_TEMPLATE/sync-plugin-docs.yml +++ b/.github/ISSUE_TEMPLATE/sync-plugin-docs.yml @@ -1,7 +1,7 @@ name: Sync Plugin Documentation description: Request synchronization of plugin documentation from influxdb3_plugins repository title: "Sync plugin docs: [PLUGIN_NAMES]" -labels: ["sync-plugin-docs", "documentation", "automation"] +labels: ["source:sync", "documentation", "automation"] assignees: [] body: - type: markdown diff --git a/.github/LABEL_GUIDE.md b/.github/LABEL_GUIDE.md new file mode 100644 index 000000000..14de67670 --- /dev/null +++ b/.github/LABEL_GUIDE.md @@ -0,0 +1,100 @@ +# Label Guide + +Label taxonomy for the docs-v2 repository. Used by automation workflows, +triage agents, and human contributors. + +## Label Definitions + +- **Product labels** (`product:*`): Derived from + [data/products.yml](../data/products.yml) — each product's `label_group` + field determines the label name, `content_path` determines which files + trigger it. Applied by the [auto-label workflow](workflows/auto-label.yml). + Multi-product PRs get all matching labels. Shared content changes get + `product:shared` plus labels for all products that reference the shared file. + +- **Source, waiting, workflow, and review labels**: Defined in + [data/labels.yml](../data/labels.yml) — names, colors, and descriptions. + +- **Review label behavior** (severity levels, result rules, result → label + mapping): Defined in + [templates/review-comment.md](templates/review-comment.md). + +Human approval uses GitHub's native PR review system (CODEOWNERS), not labels. + +## Renamed Labels + +| Old Name | New Name | +|----------|----------| +| `AI assistant tooling` | `ai:tooling` | +| `ci:testing-and-validation` | `ci:testing` | +| `design` | `area:site-ui` | +| `InfluxDB Cloud` | `product:v2-cloud` | +| `user feedback` | `source:feedback` | +| `ai:tooling` | `area:agents` | + +## Deleted Labels + +| Label | Replacement | Reason | +|-------|-------------|--------| +| `Pending PR` | `waiting:pr` | Consolidated into `waiting:` namespace | +| `broke-link` | `area:links` | Consolidated into `area:` namespace | + +## Common Workflows + +### Issue triage + +1. Read issue → identify product(s) → apply `product:*` labels +2. Apply `source:*` label if applicable +3. Determine readiness → apply `agent-ready` or `waiting:*` + +### PR review pipeline + +1. PR opened → auto-label applies `product:*` labels +2. Doc review workflow triggers (unless `skip-review` is present) +3. Copilot code review runs on the diff (uses + [`.github/instructions/`](instructions/) files from the base branch) +4. Copilot visual review checks rendered preview pages +5. Human reviewer uses GitHub's PR review for final approval + +Review labels (`review:*`) are applied manually after review, not by CI. + +### GitHub Filter Queries + +``` +# PRs needing human review +label:review:needs-human is:pr is:open + +# Agent-ready issues +label:agent-ready is:issue is:open -label:waiting:engineering -label:waiting:product + +# All InfluxDB 3 issues +label:product:v3-monolith,product:v3-distributed is:issue is:open + +# Blocked issues +label:waiting:engineering,waiting:product is:issue is:open + +# PRs that skipped review +label:skip-review is:pr +``` + +## Auto-labeling Behavior + +The [auto-label workflow](workflows/auto-label.yml) runs on +`pull_request: [opened, synchronize]` and: + +- Reads path-to-product mappings from `data/products.yml` +- Matches changed files to product labels +- Expands shared content changes to affected product labels +- Adds labels idempotently (skips labels already present) +- Skips draft and fork PRs + +## References + +- Label definitions: `data/labels.yml` +- Product definitions: `data/products.yml` +- Review comment format: `.github/templates/review-comment.md` +- Auto-label workflow: `.github/workflows/auto-label.yml` +- Doc review workflow: `.github/workflows/doc-review.yml` +- Triage agent: `.claude/agents/doc-triage-agent.md` +- Review agent: `.claude/agents/doc-review-agent.md` +- Migration scripts: `helper-scripts/label-migration/` diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index b31410cbf..975b1a0f0 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,261 +2,61 @@ > **For GitHub Copilot and other AI coding agents** > -> This is the primary instruction file for GitHub Copilot working with the InfluxData documentation site. -> > **Instruction resources**: > -> - [.github/agents/copilot-instructions-agent.md](agents/copilot-instructions-agent.md) - **Creating/improving Copilot instructions** -> - [.claude/skills/](../.claude/skills/) - **Detailed workflows** (content editing, testing, InfluxDB setup, templates) > - [.github/instructions/](instructions/) - **Pattern-specific** (auto-loaded by file type) -> - [.github/agents/](agents/) - **Specialist agents** (TypeScript/Hugo, Copilot management) -> - [AGENTS.md](../AGENTS.md), [CLAUDE.md](../CLAUDE.md) - General AI assistant guides +> - [AGENTS.md](../AGENTS.md) - Shared project guidelines (style, constraints, content structure) +> - [.github/LABEL_GUIDE.md](LABEL_GUIDE.md) - Label taxonomy and review pipeline ## Quick Reference -| Task | Command | Time | Details | -| ---------------- | ----------------------------------------------------- | ------- | ------------------------------------- | -| Install | `CYPRESS_INSTALL_BINARY=0 yarn install` | \~4s | Skip Cypress for CI | -| Build | `npx hugo --quiet` | \~75s | NEVER CANCEL | -| Dev Server | `npx hugo server` | \~92s | Port 1313 | -| Create Docs | `docs create --products ` | varies | AI-assisted scaffolding | -| Create & Open | `docs create --products --open` | instant | Non-blocking (background) | -| Create & Wait | `docs create --products --open --wait` | varies | Blocking (interactive) | -| Edit Docs | `docs edit ` | instant | Non-blocking (background) | -| Edit Docs (wait) | `docs edit --wait` | varies | Blocking (interactive) | -| List Files | `docs edit --list` | instant | Show files without opening | -| Add Placeholders | `docs placeholders ` | instant | Add placeholder syntax to code blocks | -| Audit Docs | `docs audit --products ` | varies | Audit documentation coverage | -| Release Notes | `docs release-notes --products ` | varies | Generate release notes from commits | -| Test All | `yarn test:codeblocks:all` | 15-45m | NEVER CANCEL | -| Lint | `yarn lint` | \~1m | Pre-commit checks | +| Task | Command | Time | +| ---------------- | ----------------------------------------------------- | ------- | +| Install | `CYPRESS_INSTALL_BINARY=0 yarn install` | \~4s | +| Build | `npx hugo --quiet` | \~75s | +| Dev Server | `npx hugo server` | \~92s | +| Create Docs | `docs create --products ` | varies | +| Edit Docs | `docs edit ` | instant | +| Add Placeholders | `docs placeholders ` | instant | +| Audit Docs | `docs audit --products ` | varies | +| Test All | `yarn test:codeblocks:all` | 15-45m | +| Lint | `yarn lint` | \~1m | + +**NEVER CANCEL** Hugo builds (\~75s) or test runs (15-45m). ## CLI Tools -**For when to use CLI vs direct editing**, see [docs-cli-workflow skill](../.claude/skills/docs-cli-workflow/SKILL.md). - ```bash -# Create new documentation (AI-assisted scaffolding) -docs create --products -docs create --products influxdb3_core --open # Non-blocking -docs create --products influxdb3_core --open --wait # Blocking - -# Find and edit documentation by URL -docs edit # Non-blocking (agent-friendly) -docs edit --list # List files only -docs edit --wait # Wait for editor - -# Other tools -docs placeholders # Add placeholder syntax to code blocks -docs audit --products # Audit documentation coverage -docs release-notes --products - -# Get help -docs --help -docs create --help +docs --help # Full reference ``` -**Key points**: - -- Accepts both product keys (`influxdb3_core`) and paths (`/influxdb3/core`) -- Non-blocking by default (agent-friendly) -- Use `--wait` for interactive editing -- `--products` and `--repos` are mutually exclusive for audit/release-notes +Non-blocking by default. Use `--wait` for interactive editing. ## Workflows -### Content Editing +- **Content editing**: See [content-editing skill](../.claude/skills/content-editing/SKILL.md) +- **Testing**: See [DOCS-TESTING.md](../DOCS-TESTING.md) +- **Hugo templates**: See [hugo-template-dev skill](../.claude/skills/hugo-template-dev/SKILL.md) -See [content-editing skill](../.claude/skills/content-editing/SKILL.md) for complete workflow: +## Product and Content Paths -- Creating/editing content with CLI -- Shared content management -- Testing and validation - -### Testing - -See [DOCS-TESTING.md](../DOCS-TESTING.md) and [cypress-e2e-testing skill](../.claude/skills/cypress-e2e-testing/SKILL.md). - -Quick tests (NEVER CANCEL long-running): - -```bash -yarn test:codeblocks:all # 15-45m -yarn test:links # 1-5m -yarn lint # 1m -``` - -### InfluxDB 3 Setup - -See [influxdb3-test-setup skill](../.claude/skills/influxdb3-test-setup/SKILL.md). - -Quick setup: - -```bash -./test/scripts/init-influxdb3.sh core # Per-worktree, port 8282 -./test/scripts/init-influxdb3.sh enterprise # Shared, port 8181 -./test/scripts/init-influxdb3.sh all # Both -``` - -### Hugo Template Development - -See [hugo-template-dev skill](../.claude/skills/hugo-template-dev/SKILL.md) for template syntax, data access, and testing strategies. - -## Repository Structure - -### Content Organization - -- **InfluxDB 3**: `/content/influxdb3/` (core, enterprise, cloud-dedicated, cloud-serverless, clustered, explorer) -- **InfluxDB v2**: `/content/influxdb/` (v2, cloud) -- **InfluxDB v1**: `/content/influxdb/v1` -- **InfluxDB Enterprise (v1)**: `/content/enterprise_influxdb/v1/` -- **Telegraf**: `/content/telegraf/v1/` -- **Kapacitor**: `/content/kapacitor/` -- **Chronograf**: `/content/chronograf/` -- **Flux**: `/content/flux/` -- **Examples**: `/content/example.md` (comprehensive shortcode reference) -- **Shared content**: `/content/shared/` - -### Key Files - -- **Config**: `/config/_default/`, `package.json`, `compose.yaml`, `lefthook.yml` -- **Testing**: `cypress.config.js`, `pytest.ini`, `.vale.ini` -- **Assets**: `/assets/` (JS, CSS), `/layouts/` (templates), `/data/` (YAML/JSON) -- **Build output**: `/public/` (\~529MB, gitignored) - -## Technology Stack - -- **Hugo** - Static site generator -- **Node.js/Yarn** - Package management -- **Testing**: Pytest, Cypress, link-checker, Vale -- **Tools**: Docker, ESLint, Prettier, Lefthook - -## Common Issues - -### Network Restrictions - -Commands that may fail in restricted environments: - -- Docker builds (external repos) -- `docker compose up local-dev` (Alpine packages) -- Cypress installation (use `CYPRESS_INSTALL_BINARY=0`) - -### Pre-commit Validation - -```bash -# Quick validation before commits -yarn prettier --write "**/*.{css,js,ts,jsx,tsx}" -yarn eslint assets/js/**/*.js -npx hugo --quiet -``` - -## Documentation Coverage - -- **InfluxDB 3**: Core, Enterprise, Cloud (Dedicated/Serverless), Clustered, Explorer, plugins -- **InfluxDB v2/v1**: OSS, Cloud, Enterprise -- **Tools**: Telegraf, Kapacitor, Chronograf, Flux -- **API Reference**: All InfluxDB editions +Defined in [data/products.yml](../data/products.yml). ## Content Guidelines -**Style guide**: Google Developer Documentation Style Guide\ -**Voice**: Active, present tense, second person\ -**Line breaks**: Semantic line feeds (one sentence per line)\ -**Files**: lowercase-with-hyphens.md +- [DOCS-CONTRIBUTING.md](../DOCS-CONTRIBUTING.md) - Style, workflow, commit format +- [DOCS-SHORTCODES.md](../DOCS-SHORTCODES.md) - Shortcode reference +- [DOCS-FRONTMATTER.md](../DOCS-FRONTMATTER.md) - Frontmatter reference +- [content/example.md](../content/example.md) - Working shortcode examples -### Quick Shortcodes +## File Pattern-Specific Instructions -````markdown -# Callouts (GitHub-style alerts) -> [!Note] / [!Warning] / [!Tip] / [!Important] / [!Caution] - -# Required elements -{{< req >}} -{{< req type="key" >}} - -# Code placeholders -```sh { placeholders="DATABASE_NAME|API_TOKEN" } -curl https://example.com/api?db=DATABASE_NAME -```` - -```` - -**Complete reference**: [DOCS-SHORTCODES.md](../DOCS-SHORTCODES.md) - -### Required Frontmatter - -```yaml -title: # Required -description: # Required -menu: - product_menu_key: - name: # Optional - parent: # Optional -weight: # Required: 1-99, 101-199, 201-299... -```` - -**Shared content**: Add `source: /shared/path/to/file.md` - -**Complete reference**: [DOCS-FRONTMATTER.md](../DOCS-FRONTMATTER.md) - -### Resources - -- [DOCS-CONTRIBUTING.md](../DOCS-CONTRIBUTING.md) - Workflow & guidelines -- [DOCS-SHORTCODES.md](../DOCS-SHORTCODES.md) - Complete shortcodes -- [DOCS-FRONTMATTER.md](../DOCS-FRONTMATTER.md) - Complete metadata -- [DOCS-TESTING.md](../DOCS-TESTING.md) - Testing procedures -- [content/example.md](../content/example.md) - Working examples - -## Troubleshooting - -| Issue | Solution | -| ------------------------ | ---------------------------------------------------------------- | -| Pytest collected 0 items | Use `python` not `py` for language identifier | -| Hugo build errors | Check `/config/_default/` | -| Docker build fails | Expected in restricted networks - use local Hugo | -| Cypress install fails | Use `CYPRESS_INSTALL_BINARY=0 yarn install` | -| Link validation slow | Test specific files: `yarn test:links content/file.md` | -| Vale "0 errors in stdin" | File is outside repo - Vale Docker can only access repo files | -| Vale false positives | Add terms to `.ci/vale/styles/InfluxDataDocs/Terms/ignore.txt` | -| Vale duration warnings | Duration literals (`30d`) are valid - check InfluxDataDocs.Units | - -## Specialized Instructions - -### File Pattern-Specific Instructions - -These instructions are automatically loaded by GitHub Copilot based on the files you're working with: +Auto-loaded by GitHub Copilot based on changed files: | Pattern | File | Description | | ------------------------ | ----------------------------------------------------------------- | ------------------------------------------------ | | `content/**/*.md` | [content.instructions.md](instructions/content.instructions.md) | Content file guidelines, frontmatter, shortcodes | +| `content/**/*.md` | [content-review.instructions.md](instructions/content-review.instructions.md) | Review criteria for content changes | | `layouts/**/*.html` | [layouts.instructions.md](instructions/layouts.instructions.md) | Shortcode implementation patterns and testing | | `api-docs/**/*.yml` | [api-docs.instructions.md](instructions/api-docs.instructions.md) | OpenAPI spec workflow | | `assets/js/**/*.{js,ts}` | [assets.instructions.md](instructions/assets.instructions.md) | TypeScript/JavaScript and CSS development | - -### Specialized Resources - -**Custom Agents** (`.github/agents/`): - -- [typescript-hugo-agent.md](agents/typescript-hugo-agent.md) - TypeScript/Hugo development -- [copilot-instructions-agent.md](agents/copilot-instructions-agent.md) - Managing Copilot instructions - -**Claude Skills** (`.claude/skills/` - detailed workflows): - -- [content-editing](../.claude/skills/content-editing/SKILL.md) - Complete content workflow -- [docs-cli-workflow](../.claude/skills/docs-cli-workflow/SKILL.md) - CLI decision guidance -- [cypress-e2e-testing](../.claude/skills/cypress-e2e-testing/SKILL.md) - E2E testing -- [hugo-template-dev](../.claude/skills/hugo-template-dev/SKILL.md) - Hugo templates -- [influxdb3-test-setup](../.claude/skills/influxdb3-test-setup/SKILL.md) - InfluxDB 3 setup -- [vale-linting](../.claude/skills/vale-linting/SKILL.md) - Vale configuration and debugging - -**Documentation**: - -- [DOCS-TESTING.md](../DOCS-TESTING.md) - Testing procedures -- [DOCS-CONTRIBUTING.md](../DOCS-CONTRIBUTING.md) - Contribution guidelines -- [DOCS-FRONTMATTER.md](../DOCS-FRONTMATTER.md) - Frontmatter reference -- [DOCS-SHORTCODES.md](../DOCS-SHORTCODES.md) - Shortcodes reference - -## Important Notes - -- This is a large site (5,359+ pages) with complex build processes -- **NEVER CANCEL** long-running operations (Hugo builds, tests) -- Set appropriate timeouts: Hugo build (180s+), tests (30+ minutes) diff --git a/.github/instructions/content-review.instructions.md b/.github/instructions/content-review.instructions.md new file mode 100644 index 000000000..185786556 --- /dev/null +++ b/.github/instructions/content-review.instructions.md @@ -0,0 +1,76 @@ +--- +applyTo: "content/**/*.md" +--- + +# Content Review Criteria + +Review documentation changes against these rules. Only flag issues you are +confident about. Reference the linked docs for detailed rules. + +## Frontmatter + +Rules: [DOCS-FRONTMATTER.md](../../DOCS-FRONTMATTER.md) + +- `title` and `description` are required on every page +- `menu` structure matches the product's menu key +- `weight` is present for pages in navigation +- `source` paths point to valid `/shared/` paths +- No duplicate or conflicting frontmatter keys + +## Shortcode Syntax + +Rules: [DOCS-SHORTCODES.md](../../DOCS-SHORTCODES.md) + +- `{{< >}}` for HTML output, `{{% %}}` for Markdown-processed content +- Closing tags match opening tags +- Required parameters are present +- Callouts use GitHub-style syntax: `> [!Note]`, `> [!Warning]`, etc. + +## Heading Hierarchy + +- No h1 headings in content (h1 comes from `title` frontmatter) +- Headings don't skip levels (h2 -> h4 without h3) + +## Semantic Line Feeds + +Rules: [DOCS-CONTRIBUTING.md](../../DOCS-CONTRIBUTING.md) + +- One sentence per line (better diffs) +- Long sentences on their own line, not concatenated + +## Terminology and Product Names + +Products defined in [data/products.yml](../../data/products.yml): + +- Use official names: "InfluxDB 3 Core", "InfluxDB 3 Enterprise", + "InfluxDB Cloud Serverless", "InfluxDB Cloud Dedicated" +- Don't mix v2/v3 terminology (e.g., "bucket" in v3 Core docs) +- Version references match the content path + +## Links + +- Internal links use relative paths or Hugo `relref` shortcodes +- No hardcoded `docs.influxdata.com` links in content files +- Anchor links match actual heading IDs + +## Code Blocks + +- Use `python` not `py` for language identifiers (pytest requirement) +- Long options in CLI examples (`--output` not `-o`) +- Keep lines within 80 characters +- Include language identifier on fenced code blocks + +## Shared Content + +- `source:` frontmatter points to an existing shared file +- Shared files don't contain frontmatter (only content) +- Changes to shared content affect multiple products — flag if unintentional + +## Severity + +- **BLOCKING**: Broken rendering, wrong product names, missing required + frontmatter, malformed shortcodes, h1 in content body +- **WARNING**: Missing semantic line feeds, skipped heading levels, missing + `weight`, long CLI options not used +- **INFO**: Suggestions, code block missing language identifier, opportunities + to use shared content diff --git a/.github/prompts/copilot-visual-review.md b/.github/prompts/copilot-visual-review.md new file mode 100644 index 000000000..2ce9de154 --- /dev/null +++ b/.github/prompts/copilot-visual-review.md @@ -0,0 +1,34 @@ +# Visual Review Prompt + +Review the rendered documentation pages at the preview URLs listed below. +Check each page for visual and structural issues that are invisible in the +Markdown source. + +## Checklist + +For each preview URL, verify: + +- [ ] **No raw shortcodes** — No `{{<` or `{{%` syntax visible on the page +- [ ] **No placeholder text** — No `PLACEHOLDER`, `TODO`, `FIXME`, or + template variables visible in rendered content +- [ ] **Layout intact** — No overlapping text, missing images, or collapsed + sections +- [ ] **Code blocks render correctly** — No raw HTML fences or Markdown + syntax visible inside code blocks +- [ ] **Product names correct** — Page header, breadcrumbs, and sidebar show + the correct product name +- [ ] **No 404s or errors** — Page loads without error states +- [ ] **Navigation correct** — Sidebar entries link to the right pages and + the page appears in the expected location + +## Output + +Follow the shared review comment format, severity definitions, and label +mapping in +[templates/review-comment.md](../templates/review-comment.md). + +Adapt the "Files Reviewed" section to list preview URLs instead of file +paths. + +## Preview URLs + diff --git a/.github/pull_request_template/influxdb_v1_release.md b/.github/pull_request_template/influxdb_v1_release.md index cc341db77..cbfe0e6c4 100644 --- a/.github/pull_request_template/influxdb_v1_release.md +++ b/.github/pull_request_template/influxdb_v1_release.md @@ -1,27 +1,37 @@ ## InfluxDB v1 Release Documentation -**Release Version:** v1.x.x -**Release Type:** [ ] OSS [ ] Enterprise [ ] Both +**Release Version:** v1.x.x +**Release Type:** [ ] OSS [ ] Enterprise + +> [!Important] +> **Always create separate PRs for OSS and Enterprise releases.** +> OSS can publish immediately when the GitHub release tag is available. +> Enterprise must wait until the release artifact is GA in the InfluxData portal. +> Never combine both products in a single release PR. ### Description Brief description of the release and documentation changes. +### Pre-merge Gate (Enterprise only) +- [ ] **Confirm release artifact is GA in the InfluxData portal** +- [ ] **v1 codeowner has signaled readiness** (e.g., applied a release label) + ### Release Documentation Checklist #### Release Notes - [ ] Generate release notes from changelog - - [ ] OSS: Use commit messages from GitHub release tag `https://github.com/influxdata/influxdb/releases/tag/v1.x.x` - - [ ] Enterprise: Use `https://dl.influxdata.com/enterprise/nightlies/master/CHANGELOG.md` - - [ ] **Note**: For Enterprise releases, include important updates, features, and fixes from the corresponding OSS tag + - OSS: Use commit messages from GitHub release tag `https://github.com/influxdata/influxdb/releases/tag/v1.x.x` + - Enterprise: Use `https://dl.influxdata.com/enterprise/nightlies/master/CHANGELOG.md` + - **Note**: For Enterprise releases, include important updates, features, and fixes from the corresponding OSS tag - [ ] Update release notes in appropriate location - - [ ] OSS: `/content/influxdb/v1/about_the_project/releasenotes-changelog.md` - - [ ] Enterprise: `/content/enterprise_influxdb/v1/about-the-project/release-notes.md` + - OSS: `content/influxdb/v1/about_the_project/release-notes.md` + - Enterprise: `content/enterprise_influxdb/v1/about-the-project/release-notes.md` - [ ] Ensure release notes follow documentation formatting standards #### Version Updates -- [ ] Update patch version in `/data/products.yml` - - [ ] OSS: `influxdb > v1 > latest` - - [ ] Enterprise: `enterprise_influxdb > v1 > latest` +- [ ] Update patch version in `data/products.yml` (**only for this product**) + - OSS: `influxdb > latest_patches > v1` + - Enterprise: `enterprise_influxdb > latest_patches > v1` - [ ] Update version references in documentation - [ ] Installation guides - [ ] Docker documentation @@ -37,8 +47,9 @@ Brief description of the release and documentation changes. #### Testing - [ ] Build documentation locally and verify changes render correctly - [ ] Test all updated links -- [ ] Run link validation: `yarn test:links content/influxdb/v1/**/*.md` -- [ ] Run link validation: `yarn test:links content/enterprise_influxdb/v1/**/*.md` +- [ ] Run link validation for the product being released: + - OSS: `yarn test:links content/influxdb/v1/**/*.md` + - Enterprise: `yarn test:links content/enterprise_influxdb/v1/**/*.md` ### Related Resources - DAR Issue: # @@ -50,6 +61,3 @@ Brief description of the release and documentation changes. - [ ] Verify documentation is deployed to production - [ ] Announce in #docs channel - [ ] Close related DAR issue(s) - ---- -**Note:** For Enterprise releases, ensure you have access to the Enterprise changelog and coordinate with the release team for timing. \ No newline at end of file diff --git a/.github/scripts/detect-preview-pages.js b/.github/scripts/detect-preview-pages.js index 12e255ac4..76ab1eac9 100644 --- a/.github/scripts/detect-preview-pages.js +++ b/.github/scripts/detect-preview-pages.js @@ -35,10 +35,10 @@ if (!/^origin\/[a-zA-Z0-9._\/-]+$/.test(BASE_REF)) { */ function getAllChangedFiles() { try { - const output = execSync( - `git diff --name-only ${BASE_REF}...HEAD`, - { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] } - ); + const output = execSync(`git diff --name-only ${BASE_REF}...HEAD`, { + encoding: 'utf-8', + stdio: ['pipe', 'pipe', 'pipe'], + }); return output.trim().split('\n').filter(Boolean); } catch (err) { console.error(`Error detecting changes: ${err.message}`); @@ -53,11 +53,13 @@ function getAllChangedFiles() { */ function categorizeChanges(files) { return { - content: files.filter(f => f.startsWith('content/') && f.endsWith('.md')), - layouts: files.filter(f => f.startsWith('layouts/')), - assets: files.filter(f => f.startsWith('assets/')), - data: files.filter(f => f.startsWith('data/')), - apiDocs: files.filter(f => f.startsWith('api-docs/') || f.startsWith('openapi/')), + content: files.filter((f) => f.startsWith('content/') && f.endsWith('.md')), + layouts: files.filter((f) => f.startsWith('layouts/')), + assets: files.filter((f) => f.startsWith('assets/')), + data: files.filter((f) => f.startsWith('data/')), + apiDocs: files.filter( + (f) => f.startsWith('api-docs/') || f.startsWith('openapi/') + ), }; } @@ -127,7 +129,7 @@ function main() { const htmlPaths = mapContentToPublic(expandedContent, 'public'); // Convert HTML paths to URL paths - pagesToDeploy = Array.from(htmlPaths).map(htmlPath => { + pagesToDeploy = Array.from(htmlPaths).map((htmlPath) => { return '/' + htmlPath.replace('public/', '').replace('/index.html', '/'); }); console.log(` Found ${pagesToDeploy.length} affected pages\n`); @@ -135,34 +137,53 @@ function main() { // Strategy 2: Layout/asset changes - parse URLs from PR body if (hasLayoutChanges) { - console.log('🎨 Layout/asset changes detected, checking PR description for URLs...'); + console.log( + '🎨 Layout/asset changes detected, checking PR description for URLs...' + ); + + // Auto-detect home page when the root template changes + if (changes.layouts.includes('layouts/index.html')) { + pagesToDeploy = [...new Set([...pagesToDeploy, '/'])]; + console.log( + ' 🏠 Home page template (layouts/index.html) changed - auto-adding / to preview pages' + ); + } + const prUrls = extractDocsUrls(PR_BODY); if (prUrls.length > 0) { console.log(` Found ${prUrls.length} URLs in PR description`); // Merge with content pages (deduplicate) pagesToDeploy = [...new Set([...pagesToDeploy, ...prUrls])]; - } else if (changes.content.length === 0) { - // No content changes AND no URLs specified - need author input - console.log(' ⚠️ No URLs found in PR description - author input needed'); + } else if (pagesToDeploy.length === 0) { + // No content changes, no auto-detected pages, and no URLs specified - need author input + console.log( + ' ⚠️ No URLs found in PR description - author input needed' + ); setOutput('pages-to-deploy', '[]'); setOutput('has-layout-changes', 'true'); setOutput('needs-author-input', 'true'); - setOutput('change-summary', 'Layout/asset changes detected - please specify pages to preview'); + setOutput( + 'change-summary', + 'Layout/asset changes detected - please specify pages to preview' + ); return; } } // Apply page limit if (pagesToDeploy.length > MAX_PAGES) { - console.log(`⚠️ Limiting preview to ${MAX_PAGES} pages (found ${pagesToDeploy.length})`); + console.log( + `⚠️ Limiting preview to ${MAX_PAGES} pages (found ${pagesToDeploy.length})` + ); pagesToDeploy = pagesToDeploy.slice(0, MAX_PAGES); } // Generate summary - const summary = pagesToDeploy.length > 0 - ? `${pagesToDeploy.length} page(s) will be previewed` - : 'No pages to preview'; + const summary = + pagesToDeploy.length > 0 + ? `${pagesToDeploy.length} page(s) will be previewed` + : 'No pages to preview'; console.log(`\n✅ ${summary}`); diff --git a/.github/scripts/parse-pr-urls.js b/.github/scripts/parse-pr-urls.js index 7e844fe14..58205b3b1 100644 --- a/.github/scripts/parse-pr-urls.js +++ b/.github/scripts/parse-pr-urls.js @@ -63,6 +63,9 @@ function isValidUrlPath(path) { // Must start with / if (!path.startsWith('/')) return false; + // Allow root path (docs home page at /) + if (path === '/') return true; + // Must start with known product prefix (loaded from products.yml) const validPrefixes = PRODUCT_NAMESPACES.map((ns) => `/${ns}/`); @@ -101,7 +104,8 @@ export function extractDocsUrls(text) { // Pattern 1: Full production URLs // https://docs.influxdata.com/influxdb3/core/get-started/ - const prodUrlPattern = /https?:\/\/docs\.influxdata\.com(\/[^\s)\]>"']+)/g; + // https://docs.influxdata.com/ (home page) + const prodUrlPattern = /https?:\/\/docs\.influxdata\.com(\/[^\s)\]>"']*)/g; let match; while ((match = prodUrlPattern.exec(text)) !== null) { const path = normalizeUrlPath(match[1]); @@ -112,7 +116,8 @@ export function extractDocsUrls(text) { // Pattern 2: Localhost dev URLs // http://localhost:1313/influxdb3/core/ - const localUrlPattern = /https?:\/\/localhost:\d+(\/[^\s)\]>"']+)/g; + // http://localhost:1313/ (home page) + const localUrlPattern = /https?:\/\/localhost:\d+(\/[^\s)\]>"']*)/g; while ((match = localUrlPattern.exec(text)) !== null) { const path = normalizeUrlPath(match[1]); if (isValidUrlPath(path)) { diff --git a/.github/scripts/resolve-review-urls.js b/.github/scripts/resolve-review-urls.js new file mode 100644 index 000000000..886679d35 --- /dev/null +++ b/.github/scripts/resolve-review-urls.js @@ -0,0 +1,61 @@ +/** + * Resolve Review URLs + * + * Maps changed content files to URL paths for the doc-review workflow. + * Reuses the same content-utils functions as detect-preview-pages.js. + * + * Outputs (for GitHub Actions): + * - urls: JSON array of URL paths + * - url-count: Number of URLs + */ + +import { appendFileSync } from 'fs'; +import { execSync } from 'child_process'; +import { + getChangedContentFiles, + mapContentToPublic, +} from '../../scripts/lib/content-utils.js'; + +const GITHUB_OUTPUT = process.env.GITHUB_OUTPUT || '/dev/stdout'; +const BASE_REF = process.env.BASE_REF || 'origin/master'; +const MAX_PAGES = 50; + +if (!/^origin\/[a-zA-Z0-9._/-]+$/.test(BASE_REF)) { + console.error(`Invalid BASE_REF: ${BASE_REF}`); + process.exit(1); +} + +const changed = getChangedContentFiles(BASE_REF); +const htmlPaths = mapContentToPublic(changed, 'public'); + +const contentUrls = Array.from(htmlPaths) + .sort() + .map((p) => '/' + p.replace(/^public\//, '').replace(/\/index\.html$/, '/')) + .slice(0, MAX_PAGES); + +// Check if the home page template changed (layouts/index.html → /) +let homePageUrls = []; +try { + const homePageChanged = execSync( + `git diff --name-only ${BASE_REF}...HEAD -- layouts/index.html`, + { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] } + ).trim(); + if (homePageChanged) { + homePageUrls = ['/']; + console.log( + 'Home page template (layouts/index.html) changed - adding / to review URLs' + ); + } +} catch { + // Ignore errors - fall back to content-only URLs +} + +const urls = [...new Set([...homePageUrls, ...contentUrls])].slice( + 0, + MAX_PAGES +); + +appendFileSync(GITHUB_OUTPUT, `urls=${JSON.stringify(urls)}\n`); +appendFileSync(GITHUB_OUTPUT, `url-count=${urls.length}\n`); + +console.log(`Detected ${urls.length} preview URLs`); diff --git a/.github/scripts/test-parse-pr-urls.js b/.github/scripts/test-parse-pr-urls.js index 6470122ec..36fd98d7c 100644 --- a/.github/scripts/test-parse-pr-urls.js +++ b/.github/scripts/test-parse-pr-urls.js @@ -145,7 +145,11 @@ test('Special characters: backticks are delimiters', () => { // This prevents command substitution injection const text = '/influxdb3/`whoami`/'; const result = extractDocsUrls(text); - assertEquals(result, ['/influxdb3/'], 'Should truncate at backtick delimiter'); + assertEquals( + result, + ['/influxdb3/'], + 'Should truncate at backtick delimiter' + ); }); test('Special characters: single quotes truncate at extraction', () => { @@ -257,31 +261,51 @@ test('Normalization: removes query string', () => { test('Normalization: strips wildcard from path', () => { const text = '/influxdb3/enterprise/*'; const result = extractDocsUrls(text); - assertEquals(result, ['/influxdb3/enterprise/'], 'Should strip wildcard character'); + assertEquals( + result, + ['/influxdb3/enterprise/'], + 'Should strip wildcard character' + ); }); test('Normalization: strips wildcard in middle of path', () => { const text = '/influxdb3/*/admin/'; const result = extractDocsUrls(text); - assertEquals(result, ['/influxdb3/admin/'], 'Should strip wildcard from middle of path'); + assertEquals( + result, + ['/influxdb3/admin/'], + 'Should strip wildcard from middle of path' + ); }); test('Normalization: strips multiple wildcards', () => { const text = '/influxdb3/*/admin/*'; const result = extractDocsUrls(text); - assertEquals(result, ['/influxdb3/admin/'], 'Should strip all wildcard characters'); + assertEquals( + result, + ['/influxdb3/admin/'], + 'Should strip all wildcard characters' + ); }); test('Wildcard in markdown-style notation', () => { const text = '**InfluxDB 3 Enterprise pages** (`/influxdb3/enterprise/*`)'; const result = extractDocsUrls(text); - assertEquals(result, ['/influxdb3/enterprise/'], 'Should extract and normalize path with wildcard in backticks'); + assertEquals( + result, + ['/influxdb3/enterprise/'], + 'Should extract and normalize path with wildcard in backticks' + ); }); test('Wildcard in parentheses', () => { const text = 'Affects pages under (/influxdb3/enterprise/*)'; const result = extractDocsUrls(text); - assertEquals(result, ['/influxdb3/enterprise/'], 'Should extract and normalize path with wildcard in parentheses'); + assertEquals( + result, + ['/influxdb3/enterprise/'], + 'Should extract and normalize path with wildcard in parentheses' + ); }); // Test deduplication @@ -360,6 +384,31 @@ test('BASE_REF: rejects without origin/ prefix', () => { assertEquals(isValid, false, 'Should require origin/ prefix'); }); +// Home page URL support +test('Home page: production URL https://docs.influxdata.com/', () => { + const text = 'Preview: https://docs.influxdata.com/'; + const result = extractDocsUrls(text); + assertEquals(result, ['/'], 'Should extract root path for docs home page'); +}); + +test('Home page: localhost URL http://localhost:1313/', () => { + const text = 'Testing at http://localhost:1313/'; + const result = extractDocsUrls(text); + assertEquals(result, ['/'], 'Should extract root path from localhost URL'); +}); + +test('Home page: relative root path / in text', () => { + // Relative '/' alone is not extractable by the relative pattern (requires product prefix), + // but full URLs with / path are supported + const text = 'https://docs.influxdata.com/ and /influxdb3/core/'; + const result = extractDocsUrls(text); + assertEquals( + result.sort(), + ['/', '/influxdb3/core/'].sort(), + 'Should extract both root path and product path' + ); +}); + // Print summary console.log('\n=== Test Summary ==='); console.log(`Total: ${totalTests}`); diff --git a/.github/scripts/workflow-utils.js b/.github/scripts/workflow-utils.js new file mode 100644 index 000000000..38f49695a --- /dev/null +++ b/.github/scripts/workflow-utils.js @@ -0,0 +1,104 @@ +/** + * Workflow Utilities + * + * Canonical import for GitHub Actions workflow scripts. Re-exports shared + * utilities from scripts/lib/ and adds workflow-specific helpers. + * + * Usage from github-script inline steps: + * + * const utils = await import(`${process.cwd()}/.github/scripts/workflow-utils.js`); + * const pathToLabel = await utils.getProductLabelMap(); + * const labels = utils.matchFilesToLabels(changedFiles, pathToLabel); + * + * Usage from .github/scripts/ ESM modules: + * + * import { getProductLabelMap, findPagesReferencingSharedContent } from './workflow-utils.js'; + */ + +import { readFileSync } from 'fs'; +import { findPagesReferencingSharedContent } from '../../scripts/lib/content-utils.js'; + +// --- Re-export content utilities --- +export { + findPagesReferencingSharedContent, + expandSharedContentChanges, + getChangedContentFiles, + mapContentToPublic, + categorizeContentFiles, + getSourceFromFrontmatter, +} from '../../scripts/lib/content-utils.js'; + +/** + * Build a Map of content path prefixes to product label names + * by reading data/products.yml. + * + * Requires `js-yaml` to be installed (e.g., `npm install js-yaml`). + * + * @param {string} [productsPath='data/products.yml'] - Path to products.yml + * @returns {Promise>} Map of "content/{path}/" → "product:{label_group}" + */ +export async function getProductLabelMap(productsPath = 'data/products.yml') { + const { load } = await import('js-yaml'); + const products = load(readFileSync(productsPath, 'utf8')); + const pathToLabel = new Map(); + + for (const product of Object.values(products)) { + const cp = product.content_path; + const lg = product.label_group; + if (!cp || !lg) continue; + + if (typeof cp === 'string' && typeof lg === 'string') { + pathToLabel.set(`content/${cp}/`, `product:${lg}`); + } else if (typeof cp === 'object' && typeof lg === 'object') { + for (const version of Object.keys(cp)) { + if (lg[version]) { + pathToLabel.set(`content/${cp[version]}/`, `product:${lg[version]}`); + } + } + } + } + + return pathToLabel; +} + +/** + * Match a list of file paths against the product label map. + * For shared content files, expands to find affected products. + * + * @param {string[]} files - Changed file paths + * @param {Map} pathToLabel - From getProductLabelMap() + * @returns {Set} Set of label names to apply + */ +export function matchFilesToLabels(files, pathToLabel) { + const labels = new Set(); + + for (const file of files) { + if (file.startsWith('content/shared/')) { + labels.add('product:shared'); + + try { + const referencingPages = findPagesReferencingSharedContent(file); + for (const page of referencingPages) { + for (const [prefix, label] of pathToLabel) { + if (page.startsWith(prefix)) { + labels.add(label); + break; + } + } + } + } catch { + // Shared content expansion failed — product:shared still applied + } + continue; + } + + for (const [prefix, label] of pathToLabel) { + if (file.startsWith(prefix)) { + labels.add(label); + break; + } + } + } + + return labels; +} diff --git a/.github/templates/review-comment.md b/.github/templates/review-comment.md new file mode 100644 index 000000000..790ff2912 --- /dev/null +++ b/.github/templates/review-comment.md @@ -0,0 +1,98 @@ +# Review Comment Format + +Shared definitions for severity levels, comment structure, and result → label +mapping. Used by doc-review-agent.md (local review sessions) and +copilot-visual-review.md (rendered page review). + +## Severity Levels + +### BLOCKING + +Issues that will cause incorrect rendering, broken pages, or misleading +content. These must be fixed before merge. + +Examples: +- Missing required frontmatter (`title`, `description`) +- Unclosed or malformed shortcode tags +- Wrong product name in content (e.g., "InfluxDB 3" in v2 docs) +- Broken `source:` path for shared content +- h1 heading in content body +- Raw shortcode syntax visible on rendered page (`{{<` or `{{%`) +- 404 errors on preview pages +- Wrong product name in header or breadcrumbs + +### WARNING + +Style issues or minor visual problems that should be fixed but don't break +functionality or correctness. + +Examples: +- Missing semantic line feeds (multiple sentences on one line) +- Heading level skipped (h2 → h4) +- Long option not used in CLI examples (`-o` instead of `--output`) +- Missing `weight` in frontmatter +- Minor layout issues (overlapping text, collapsed sections) +- Missing images +- Placeholder text visible (`TODO`, `FIXME`) + +### INFO + +Suggestions and observations. Not problems. + +Examples: +- Opportunity to use a shared content file +- Unusually long page that could be split +- Code block missing language identifier +- Cosmetic improvements + +## Comment Structure + +Post a single review comment on the PR with this structure: + +```markdown +## Doc Review Summary + +**Result:** APPROVED | CHANGES REQUESTED | NEEDS HUMAN REVIEW + +### Issues Found + +#### BLOCKING + +- **file:line** — Description of the issue + - Suggested fix: ... + +#### WARNING + +- **file:line** — Description of the issue + +#### INFO + +- **file:line** — Observation + +### Files Reviewed + +- `path/to/file.md` — Brief summary of changes +``` + +Adapt the "Files Reviewed" section to the review context: +- **Source review:** list file paths from the diff +- **Visual review (Copilot):** list preview URLs instead of file paths + +## Result Rules + +- Zero BLOCKING issues → **APPROVED** +- Any BLOCKING issues → **CHANGES REQUESTED** +- Cannot determine severity or diff is ambiguous → **NEEDS HUMAN REVIEW** +- Only report issues you are confident about. Do not guess. +- Group issues by file when multiple issues exist in the same file. + +## Result → Label Mapping + +| Result | Label | +|--------|-------| +| APPROVED | `review:approved` | +| CHANGES REQUESTED | `review:changes-requested` | +| NEEDS HUMAN REVIEW | `review:needs-human` | + +Labels are mutually exclusive. Apply manually after review — Copilot code +review uses GitHub's native "Comment" review type and does not manage labels. diff --git a/.github/workflows/auto-label.yml b/.github/workflows/auto-label.yml new file mode 100644 index 000000000..7dfccb43c --- /dev/null +++ b/.github/workflows/auto-label.yml @@ -0,0 +1,122 @@ +name: Auto-label PRs + +on: + pull_request: + types: [opened, synchronize] + workflow_dispatch: + inputs: + pr_number: + description: 'PR number to label' + required: true + type: number + +permissions: {} + +concurrency: + group: auto-label-${{ github.event.number || inputs.pr_number }} + cancel-in-progress: true + +jobs: + auto-label: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + # Skip draft PRs and fork PRs (workflow_dispatch always runs) + if: | + github.event_name == 'workflow_dispatch' || + (!github.event.pull_request.draft && + github.event.pull_request.head.repo.full_name == github.repository) + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + sparse-checkout: | + content + data/products.yml + scripts/lib/content-utils.js + .github/scripts/workflow-utils.js + package.json + sparse-checkout-cone-mode: false + + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22 + + - name: Install js-yaml + run: npm install --no-save --ignore-scripts --no-package-lock --legacy-peer-deps js-yaml + + - name: Apply product labels + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + with: + script: | + const { + getProductLabelMap, + matchFilesToLabels, + } = await import( + `${process.cwd()}/.github/scripts/workflow-utils.js` + ); + + const prNumber = + context.issue.number || + Number('${{ inputs.pr_number }}'); + + if (!prNumber) { + core.setFailed('No PR number available'); + return; + } + + // --- Build path-to-label mapping from products.yml --- + const pathToLabel = await getProductLabelMap(); + core.info( + `Loaded ${pathToLabel.size} path-to-label mappings from products.yml` + ); + + // --- Get changed files from the PR (paginated) --- + const files = await github.paginate( + github.rest.pulls.listFiles, + { + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + per_page: 100, + } + ); + + const changedFiles = files.map(f => f.filename); + core.info(`PR has ${changedFiles.length} changed files`); + + // --- Match files to product labels --- + const labelsToAdd = matchFilesToLabels(changedFiles, pathToLabel); + + if (labelsToAdd.size === 0) { + core.info('No product labels to add'); + return; + } + + // --- Get existing PR labels to avoid duplicates --- + const { data: prData } = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + + const existingLabels = new Set(prData.labels.map(l => l.name)); + const newLabels = [...labelsToAdd].filter( + l => !existingLabels.has(l) + ); + + if (newLabels.length === 0) { + core.info('All matching labels already present'); + return; + } + + // --- Apply labels --- + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: newLabels, + }); + + core.info(`Added labels: ${newLabels.join(', ')}`); diff --git a/.github/workflows/daily-repo-status.lock.yml b/.github/workflows/daily-repo-status.lock.yml new file mode 100644 index 000000000..edc867af7 --- /dev/null +++ b/.github/workflows/daily-repo-status.lock.yml @@ -0,0 +1,1031 @@ +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ +# | _ |/ _` |/ _ \ '_ \| __| |/ __| +# | | | | (_| | __/ | | | |_| | (__ +# \_| |_/\__, |\___|_| |_|\__|_|\___| +# __/ | +# _ _ |___/ +# | | | | / _| | +# | | | | ___ _ __ _ __| |_| | _____ ____ +# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| +# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ +# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ +# +# This file was automatically generated by gh-aw (v0.61.1). DO NOT EDIT. +# +# To update this file, edit githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11 and run: +# gh aw compile +# Not all edits will cause changes to this file. +# +# For more information: https://github.github.com/gh-aw/introduction/overview/ +# +# This workflow creates daily repo status reports. It gathers recent repository +# activity (issues, PRs, discussions, releases, code changes) and generates +# engaging GitHub issues with productivity insights, community highlights, +# and project recommendations. +# +# Source: githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11 +# +# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"82c0ab85cfbd9b16bfb39799060eb64e360b5ea0fe071ce52866b333afe5e4e5","compiler_version":"v0.61.1","strict":true} + +name: "Daily Repo Status" +"on": + schedule: + - cron: "52 7 * * *" + # Friendly format: daily (scattered) + workflow_dispatch: + +permissions: {} + +concurrency: + group: "gh-aw-${{ github.workflow }}" + +run-name: "Daily Repo Status" + +jobs: + activation: + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + comment_id: "" + comment_repo: "" + lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} + model: ${{ steps.generate_aw_info.outputs.model }} + secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@be0029bbbaeef8c6bea6825f31d9593219b2dc28 # v0.61.1 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Generate agentic run info + id: generate_aw_info + env: + GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + GH_AW_INFO_VERSION: "" + GH_AW_INFO_AGENT_VERSION: "latest" + GH_AW_INFO_CLI_VERSION: "v0.61.1" + GH_AW_INFO_WORKFLOW_NAME: "Daily Repo Status" + GH_AW_INFO_EXPERIMENTAL: "false" + GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" + GH_AW_INFO_STAGED: "false" + GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]' + GH_AW_INFO_FIREWALL_ENABLED: "true" + GH_AW_INFO_AWF_VERSION: "v0.24.2" + GH_AW_INFO_AWMG_VERSION: "" + GH_AW_INFO_FIREWALL_TYPE: "squid" + GH_AW_COMPILED_STRICT: "true" + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); + await main(core, context); + - name: Validate COPILOT_GITHUB_TOKEN secret + id: validate-secret + run: ${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + - name: Checkout .github and .agents folders + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + sparse-checkout: | + .github + .agents + sparse-checkout-cone-mode: true + fetch-depth: 1 + - name: Check workflow file timestamps + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_WORKFLOW_FILE: "daily-repo-status.lock.yml" + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); + await main(); + - name: Create prompt with built-in context + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh + { + cat << 'GH_AW_PROMPT_EOF' + + GH_AW_PROMPT_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_EOF' + + Tools: create_issue, missing_tool, missing_data, noop + + + The following GitHub context information is available for this workflow: + {{#if __GH_AW_GITHUB_ACTOR__ }} + - **actor**: __GH_AW_GITHUB_ACTOR__ + {{/if}} + {{#if __GH_AW_GITHUB_REPOSITORY__ }} + - **repository**: __GH_AW_GITHUB_REPOSITORY__ + {{/if}} + {{#if __GH_AW_GITHUB_WORKSPACE__ }} + - **workspace**: __GH_AW_GITHUB_WORKSPACE__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} + - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} + - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} + - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} + - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{/if}} + {{#if __GH_AW_GITHUB_RUN_ID__ }} + - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ + {{/if}} + + + GH_AW_PROMPT_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" + cat << 'GH_AW_PROMPT_EOF' + + GH_AW_PROMPT_EOF + cat << 'GH_AW_PROMPT_EOF' + {{#runtime-import .github/workflows/daily-repo-status.md}} + GH_AW_PROMPT_EOF + } > "$GH_AW_PROMPT" + - name: Interpolate variables and render templates + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); + await main(); + - name: Substitute placeholders + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + + const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); + + // Call the substitution function + return await substitutePlaceholders({ + file: process.env.GH_AW_PROMPT, + substitutions: { + GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, + GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, + GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, + GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, + GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE + } + }); + - name: Validate prompt placeholders + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + run: bash ${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh + - name: Print prompt + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + run: bash ${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh + - name: Upload activation artifact + if: success() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: activation + path: | + /tmp/gh-aw/aw_info.json + /tmp/gh-aw/aw-prompts/prompt.txt + retention-days: 1 + + agent: + needs: activation + runs-on: ubuntu-latest + permissions: + contents: read + issues: read + pull-requests: read + concurrency: + group: "gh-aw-copilot-${{ github.workflow }}" + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GH_AW_ASSETS_ALLOWED_EXTS: "" + GH_AW_ASSETS_BRANCH: "" + GH_AW_ASSETS_MAX_SIZE_KB: 0 + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + GH_AW_WORKFLOW_ID_SANITIZED: dailyrepostatus + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }} + model: ${{ needs.activation.outputs.model }} + output: ${{ steps.collect_output.outputs.output }} + output_types: ${{ steps.collect_output.outputs.output_types }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@be0029bbbaeef8c6bea6825f31d9593219b2dc28 # v0.61.1 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Set runtime paths + run: | + echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" >> "$GITHUB_ENV" + echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" >> "$GITHUB_ENV" + echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" >> "$GITHUB_ENV" + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Create gh-aw temp directory + run: bash ${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh + - name: Configure gh CLI for GitHub Enterprise + run: bash ${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh + env: + GH_TOKEN: ${{ github.token }} + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Checkout PR branch + id: checkout-pr + if: | + (github.event.pull_request) || (github.event.issue.pull_request) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); + await main(); + - name: Install GitHub Copilot CLI + run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest + env: + GH_HOST: github.com + - name: Install AWF binary + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.24.2 + - name: Determine automatic lockdown mode for GitHub MCP Server + id: determine-automatic-lockdown + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + with: + script: | + const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); + await determineAutomaticLockdown(github, context, core); + - name: Download container images + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.24.2 ghcr.io/github/gh-aw-firewall/api-proxy:0.24.2 ghcr.io/github/gh-aw-firewall/squid:0.24.2 ghcr.io/github/gh-aw-mcpg:v0.1.17 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine + - name: Write Safe Outputs Config + run: | + mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' + {"create_issue":{"max":1},"mentions":{"enabled":false},"missing_data":{},"missing_tool":{},"noop":{"max":1}} + GH_AW_SAFE_OUTPUTS_CONFIG_EOF + - name: Write Safe Outputs Tools + run: | + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF' + { + "description_suffixes": { + "create_issue": " CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[repo-status] \". Labels [\"report\" \"daily-status\"] will be automatically added." + }, + "repo_params": {}, + "dynamic_tools": [] + } + GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF' + { + "create_issue": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "labels": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "parent": { + "issueOrPRNumber": true + }, + "repo": { + "type": "string", + "maxLength": 256 + }, + "temporary_id": { + "type": "string" + }, + "title": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "missing_data": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "context": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "data_type": { + "type": "string", + "sanitize": true, + "maxLength": 128 + }, + "reason": { + "type": "string", + "sanitize": true, + "maxLength": 256 + } + } + }, + "missing_tool": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 512 + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "tool": { + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "noop": { + "defaultMax": 1, + "fields": { + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + } + } + } + } + GH_AW_SAFE_OUTPUTS_VALIDATION_EOF + node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs + - name: Generate Safe Outputs MCP Server Config + id: safe-outputs-config + run: | + # Generate a secure random API key (360 bits of entropy, 40+ chars) + # Mask immediately to prevent timing vulnerabilities + API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${API_KEY}" + + PORT=3001 + + # Set outputs for next steps + { + echo "safe_outputs_api_key=${API_KEY}" + echo "safe_outputs_port=${PORT}" + } >> "$GITHUB_OUTPUT" + + echo "Safe Outputs MCP server will run on port ${PORT}" + + - name: Start Safe Outputs MCP HTTP Server + id: safe-outputs-start + env: + DEBUG: '*' + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + run: | + # Environment variables are set above to prevent template injection + export DEBUG + export GH_AW_SAFE_OUTPUTS_PORT + export GH_AW_SAFE_OUTPUTS_API_KEY + export GH_AW_SAFE_OUTPUTS_TOOLS_PATH + export GH_AW_SAFE_OUTPUTS_CONFIG_PATH + export GH_AW_MCP_LOG_DIR + + bash ${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh + + - name: Start MCP Gateway + id: start-mcp-gateway + env: + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} + GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} + GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + set -eo pipefail + mkdir -p /tmp/gh-aw/mcp-config + + # Export gateway environment variables for MCP config and gateway script + export MCP_GATEWAY_PORT="80" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${MCP_GATEWAY_API_KEY}" + export MCP_GATEWAY_API_KEY + export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" + mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" + export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" + export DEBUG="*" + + export GH_AW_ENGINE="copilot" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.17' + + mkdir -p /home/runner/.copilot + cat << GH_AW_MCP_CONFIG_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + { + "mcpServers": { + "github": { + "type": "stdio", + "container": "ghcr.io/github/github-mcp-server:v0.32.0", + "env": { + "GITHUB_HOST": "\${GITHUB_SERVER_URL}", + "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_READ_ONLY": "1", + "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" + }, + "guard-policies": { + "allow-only": { + "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY", + "repos": "$GITHUB_MCP_GUARD_REPOS" + } + } + }, + "safeoutputs": { + "type": "http", + "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", + "headers": { + "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + }, + "guard-policies": { + "write-sink": { + "accept": [ + "*" + ] + } + } + } + }, + "gateway": { + "port": $MCP_GATEWAY_PORT, + "domain": "${MCP_GATEWAY_DOMAIN}", + "apiKey": "${MCP_GATEWAY_API_KEY}", + "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" + } + } + GH_AW_MCP_CONFIG_EOF + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw + - name: Clean git credentials + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh + - name: Execute GitHub Copilot CLI + id: agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 20 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.24.2 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json + GH_AW_PHASE: agent + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_VERSION: v0.61.1 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Detect inference access error + id: detect-inference-error + if: always() + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/detect_inference_access_error.sh + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Copy Copilot session state files to logs + if: always() + continue-on-error: true + run: | + # Copy Copilot session state files to logs folder for artifact collection + # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them + SESSION_STATE_DIR="$HOME/.copilot/session-state" + LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" + + if [ -d "$SESSION_STATE_DIR" ]; then + echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" + mkdir -p "$LOGS_DIR" + cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true + echo "Session state files copied successfully" + else + echo "No session-state directory found at $SESSION_STATE_DIR" + fi + - name: Stop MCP Gateway + if: always() + continue-on-error: true + env: + MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} + MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" + - name: Redact secrets in logs + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); + await main(); + env: + GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Append agent step summary + if: always() + run: bash ${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh + - name: Copy Safe Outputs + if: always() + run: | + mkdir -p /tmp/gh-aw + cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true + - name: Ingest agent output + id: collect_output + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" + GH_AW_ALLOWED_GITHUB_REFS: "" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs'); + await main(); + - name: Parse agent logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); + await main(); + - name: Parse MCP Gateway logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs'); + await main(); + - name: Print firewall logs + if: always() + continue-on-error: true + env: + AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs + run: | + # Fix permissions on firewall logs so they can be uploaded as artifacts + # AWF runs with sudo, creating files owned by root + sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true + # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) + if command -v awf &> /dev/null; then + awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" + else + echo 'AWF binary not installed, skipping firewall log summary' + fi + - name: Upload agent artifacts + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: agent + path: | + /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/sandbox/agent/logs/ + /tmp/gh-aw/redacted-urls.log + /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/sandbox/firewall/logs/ + /tmp/gh-aw/agent-stdio.log + /tmp/gh-aw/agent/ + /tmp/gh-aw/safeoutputs.jsonl + /tmp/gh-aw/agent_output.json + if-no-files-found: ignore + # --- Threat Detection (inline) --- + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }} + HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Daily Repo Status" + WORKFLOW_DESCRIPTION: "This workflow creates daily repo status reports. It gathers recent repository\nactivity (issues, PRs, discussions, releases, code changes) and generates\nengaging GitHub issues with productivity insights, community highlights,\nand project recommendations." + HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs'); + await main(); + - name: Ensure threat-detection directory and log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_agentic_execution + # Copilot CLI tool arguments (sorted): + # --allow-tool shell(cat) + # --allow-tool shell(grep) + # --allow-tool shell(head) + # --allow-tool shell(jq) + # --allow-tool shell(ls) + # --allow-tool shell(tail) + # --allow-tool shell(wc) + timeout-minutes: 20 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.24.2 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + GH_AW_PHASE: detection + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_VERSION: v0.61.1 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Parse threat detection results + id: parse_detection_results + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); + await main(); + - name: Upload threat detection log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: detection + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Set detection conclusion + id: detection_conclusion + if: always() + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }} + run: | + if [[ "$RUN_DETECTION" != "true" ]]; then + echo "conclusion=skipped" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection was not needed, marking as skipped" + elif [[ "$DETECTION_SUCCESS" == "true" ]]; then + echo "conclusion=success" >> "$GITHUB_OUTPUT" + echo "success=true" >> "$GITHUB_OUTPUT" + echo "Detection passed successfully" + else + echo "conclusion=failure" >> "$GITHUB_OUTPUT" + echo "success=false" >> "$GITHUB_OUTPUT" + echo "Detection found issues" + fi + + conclusion: + needs: + - activation + - agent + - safe_outputs + if: (always()) && ((needs.agent.result != 'skipped') || (needs.activation.outputs.lockdown_check_failed == 'true')) + runs-on: ubuntu-slim + permissions: + contents: read + issues: write + concurrency: + group: "gh-aw-conclusion-daily-repo-status" + cancel-in-progress: false + outputs: + noop_message: ${{ steps.noop.outputs.noop_message }} + tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} + total_count: ${{ steps.missing_tool.outputs.total_count }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@be0029bbbaeef8c6bea6825f31d9593219b2dc28 # v0.61.1 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_ENV" + - name: Process No-Op Messages + id: noop + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_NOOP_MAX: "1" + GH_AW_WORKFLOW_NAME: "Daily Repo Status" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/9a76aba267225767b9b2e1623188d11ed9b58f11/workflows/daily-repo-status.md" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/noop.cjs'); + await main(); + - name: Record Missing Tool + id: missing_tool + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Daily Repo Status" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/9a76aba267225767b9b2e1623188d11ed9b58f11/workflows/daily-repo-status.md" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs'); + await main(); + - name: Handle Agent Failure + id: handle_agent_failure + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Daily Repo Status" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/9a76aba267225767b9b2e1623188d11ed9b58f11/workflows/daily-repo-status.md" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_WORKFLOW_ID: "daily-repo-status" + GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} + GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_GROUP_REPORTS: "false" + GH_AW_FAILURE_REPORT_AS_ISSUE: "true" + GH_AW_TIMEOUT_MINUTES: "20" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs'); + await main(); + - name: Handle No-Op Message + id: handle_noop_message + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Daily Repo Status" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/9a76aba267225767b9b2e1623188d11ed9b58f11/workflows/daily-repo-status.md" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} + GH_AW_NOOP_REPORT_AS_ISSUE: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); + await main(); + + safe_outputs: + needs: agent + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true') + runs-on: ubuntu-slim + permissions: + contents: read + issues: write + timeout-minutes: 15 + env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/daily-repo-status" + GH_AW_ENGINE_ID: "copilot" + GH_AW_WORKFLOW_ID: "daily-repo-status" + GH_AW_WORKFLOW_NAME: "Daily Repo Status" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/9a76aba267225767b9b2e1623188d11ed9b58f11/workflows/daily-repo-status.md" + outputs: + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} + create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} + created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }} + created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }} + process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} + process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@be0029bbbaeef8c6bea6825f31d9593219b2dc28 # v0.61.1 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_ENV" + - name: Configure GH_HOST for enterprise compatibility + shell: bash + run: | + # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct + # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. + GH_HOST="${GITHUB_SERVER_URL#https://}" + GH_HOST="${GH_HOST#http://}" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" + - name: Process Safe Outputs + id: process_safe_outputs + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"close_older_issues\":true,\"labels\":[\"report\",\"daily-status\"],\"max\":1,\"title_prefix\":\"[repo-status] \"},\"missing_data\":{},\"missing_tool\":{}}" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); + await main(); + - name: Upload Safe Output Items Manifest + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: safe-output-items + path: /tmp/safe-output-items.jsonl + if-no-files-found: warn + diff --git a/.github/workflows/daily-repo-status.md b/.github/workflows/daily-repo-status.md new file mode 100644 index 000000000..bfb75e29c --- /dev/null +++ b/.github/workflows/daily-repo-status.md @@ -0,0 +1,58 @@ +--- +description: | + This workflow creates daily repo status reports. It gathers recent repository + activity (issues, PRs, discussions, releases, code changes) and generates + engaging GitHub issues with productivity insights, community highlights, + and project recommendations. + +on: + schedule: daily + workflow_dispatch: + +permissions: + contents: read + issues: read + pull-requests: read + +network: defaults + +tools: + github: + # If in a public repo, setting `lockdown: false` allows + # reading issues, pull requests and comments from 3rd-parties + # If in a private repo this has no particular effect. + lockdown: false + +safe-outputs: + mentions: false + allowed-github-references: [] + create-issue: + title-prefix: "[repo-status] " + labels: [report, daily-status] + close-older-issues: true +source: githubnext/agentics/workflows/daily-repo-status.md@9a76aba267225767b9b2e1623188d11ed9b58f11 +engine: copilot +--- + +# Daily Repo Status + +Create an upbeat daily status report for the repo as a GitHub issue. + +## What to include + +- Recent repository activity (issues, PRs, discussions, releases, code changes) +- Progress tracking, goal reminders and highlights +- Project status and recommendations +- Actionable next steps for maintainers + +## Style + +- Be positive, encouraging, and helpful 🌟 +- Use emojis moderately for engagement +- Keep it concise - adjust length based on actual activity + +## Process + +1. Gather recent activity from the repository +2. Study the repository, its issues and its pull requests +3. Create a new GitHub issue with your findings and insights \ No newline at end of file diff --git a/.github/workflows/doc-review.yml b/.github/workflows/doc-review.yml new file mode 100644 index 000000000..b6f79cffa --- /dev/null +++ b/.github/workflows/doc-review.yml @@ -0,0 +1,280 @@ +name: Doc Review + +on: + pull_request: + types: [opened, synchronize, ready_for_review] + paths: + - 'content/**' + - 'layouts/**' + - 'assets/**' + - 'data/**' + workflow_dispatch: + inputs: + pr_number: + description: 'PR number to review' + required: true + type: number + +permissions: {} + +concurrency: + group: doc-review-${{ github.event.number || inputs.pr_number }} + cancel-in-progress: true + +jobs: + # ----------------------------------------------------------------- + # Job 1: Resolve preview URLs from changed content files + # ----------------------------------------------------------------- + resolve-urls: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + if: | + github.event_name == 'workflow_dispatch' || + (!github.event.pull_request.draft && + github.event.pull_request.head.repo.full_name == github.repository && + !contains(github.event.pull_request.labels.*.name, 'skip-review')) + outputs: + urls: ${{ steps.detect.outputs.urls }} + url-count: ${{ steps.detect.outputs.url-count }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + fetch-depth: 0 + sparse-checkout: | + content + data/products.yml + scripts/lib/content-utils.js + .github/scripts/resolve-review-urls.js + package.json + sparse-checkout-cone-mode: false + + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22 + + - name: Resolve base ref + id: base + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }} + run: | + if [ -n "${{ github.base_ref }}" ]; then + echo "ref=origin/${{ github.base_ref }}" >> "$GITHUB_OUTPUT" + else + BASE=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json baseRefName -q .baseRefName) + git fetch origin "$BASE" + echo "ref=origin/$BASE" >> "$GITHUB_OUTPUT" + fi + + - name: Detect changed pages + id: detect + env: + BASE_REF: ${{ steps.base.outputs.ref }} + run: node .github/scripts/resolve-review-urls.js + + # ----------------------------------------------------------------- + # Job 2: Copilot code review (runs in parallel with Job 1) + # ----------------------------------------------------------------- + copilot-review: + runs-on: ubuntu-latest + permissions: + pull-requests: write + if: | + github.event_name == 'workflow_dispatch' || + (!github.event.pull_request.draft && + github.event.pull_request.head.repo.full_name == github.repository && + !contains(github.event.pull_request.labels.*.name, 'skip-review')) + steps: + - name: Request Copilot review + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + env: + PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }} + with: + script: | + const prNumber = context.issue.number || Number(process.env.PR_NUMBER); + try { + await github.rest.pulls.requestReviewers({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + reviewers: ['copilot-pull-request-reviewer'], + }); + core.info('Copilot code review requested successfully'); + } catch (error) { + core.warning(`Could not request Copilot review: ${error.message}`); + core.warning( + 'To enable automatic Copilot reviews, configure a repository ruleset: ' + + 'Settings → Rules → Rulesets → "Automatically request Copilot code review"' + ); + } + + # ----------------------------------------------------------------- + # Job 3: Copilot visual review (depends on Job 1 for URLs) + # ----------------------------------------------------------------- + copilot-visual-review: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + needs: resolve-urls + if: needs.resolve-urls.result == 'success' && fromJson(needs.resolve-urls.outputs.url-count) > 0 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + sparse-checkout: .github/prompts/copilot-visual-review.md + sparse-checkout-cone-mode: false + + - name: Wait for preview deployment + id: wait + env: + PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }} + run: | + PREVIEW_URL="https://influxdata.github.io/docs-v2/pr-preview/pr-${PR_NUMBER}/" + TIMEOUT=600 # 10 minutes + INTERVAL=15 + ELAPSED=0 + + echo "Waiting for preview at ${PREVIEW_URL}" + + while [ "$ELAPSED" -lt "$TIMEOUT" ]; do + STATUS=$(curl -s -o /dev/null -L -w "%{http_code}" "$PREVIEW_URL" || echo "000") + if [ "$STATUS" = "200" ]; then + echo "Preview is live" + echo "available=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "Status: ${STATUS} (${ELAPSED}s / ${TIMEOUT}s)" + sleep "$INTERVAL" + ELAPSED=$((ELAPSED + INTERVAL)) + done + + echo "Preview deployment timed out after ${TIMEOUT}s" + echo "available=false" >> "$GITHUB_OUTPUT" + + - name: Post visual review request + if: steps.wait.outputs.available == 'true' + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + env: + PREVIEW_URLS: ${{ needs.resolve-urls.outputs.urls }} + PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }} + with: + script: | + const fs = require('fs'); + + let urls; + try { + urls = JSON.parse(process.env.PREVIEW_URLS); + } catch (e) { + core.warning(`Failed to parse PREVIEW_URLS: ${e.message}`); + return; + } + + const prNumber = context.issue.number || Number(process.env.PR_NUMBER); + const previewBase = `https://influxdata.github.io/docs-v2/pr-preview/pr-${prNumber}`; + + // Build preview URL list + const urlList = urls + .map(u => `- [${u}](${previewBase}${u})`) + .join('\n'); + + // Read the Copilot visual review template + const template = fs.readFileSync( + '.github/prompts/copilot-visual-review.md', + 'utf8' + ); + + const marker = ''; + const body = [ + marker, + '## Preview Pages for Review', + '', + `${urls.length} page(s) changed in this PR:`, + '', + '
', + 'Preview URLs', + '', + urlList, + '', + '
', + '', + '---', + '', + `@github-copilot please review the preview pages listed above using the template below:`, + '', + template.trim(), + '', + urlList, + ].join('\n'); + + // Update existing comment or create new one + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + const existing = comments.find(c => c.body.includes(marker)); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body, + }); + } + + core.info(`Posted visual review request with ${urls.length} URLs`); + + - name: Post timeout notice + if: steps.wait.outputs.available == 'false' + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + env: + PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }} + with: + script: | + const prNumber = context.issue.number || Number(process.env.PR_NUMBER); + const marker = ''; + const body = [ + marker, + '## Visual Review Skipped', + '', + 'The PR preview deployment did not become available within 10 minutes.', + 'Visual review was skipped. The Copilot code review (Job 2) still ran.', + '', + 'To trigger visual review manually, re-run this workflow after the', + 'preview is deployed.', + ].join('\n'); + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + const existing = comments.find(c => c.body.includes(marker)); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body, + }); + } diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index 0eb5d6b42..85aaf11d1 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -2,7 +2,7 @@ name: PR Preview on: pull_request: - types: [opened, reopened, synchronize, closed] + types: [opened, reopened, synchronize, closed, ready_for_review] paths: - 'content/**' - 'layouts/**' @@ -139,6 +139,8 @@ jobs: - name: Deploy preview if: steps.detect.outputs.pages-to-deploy != '[]' + id: deploy-preview + continue-on-error: true uses: rossjrw/pr-preview-action@v1.4.8 with: source-dir: ./preview-staging @@ -146,8 +148,27 @@ jobs: umbrella-dir: pr-preview action: deploy - - name: Post success comment + - name: Validate preview deployment if: steps.detect.outputs.pages-to-deploy != '[]' + id: validate-deploy + run: | + DEPLOY_OUTCOME="${{ steps.deploy-preview.outcome }}" + DEPLOY_URL="${{ steps.deploy-preview.outputs.deployment-url }}" + + if [ -z "$DEPLOY_URL" ]; then + echo "Deployment step did not produce a preview URL. Failing preview job." + exit 1 + fi + + if [ "$DEPLOY_OUTCOME" != "success" ]; then + echo "Deployment reported outcome: $DEPLOY_OUTCOME" + echo "Preview URL exists; treating as transient post-deploy comment error." + fi + + echo "status=ok" >> "$GITHUB_OUTPUT" + + - name: Post success comment + if: steps.detect.outputs.pages-to-deploy != '[]' && steps.validate-deploy.outputs.status == 'ok' uses: actions/github-script@v7 with: script: | diff --git a/.github/workflows/sync-plugins.yml b/.github/workflows/sync-plugins.yml index 50c9ecb4e..d840f4247 100644 --- a/.github/workflows/sync-plugins.yml +++ b/.github/workflows/sync-plugins.yml @@ -25,7 +25,7 @@ jobs: # Only run on issues with sync-plugin-docs label or manual dispatch if: | github.event_name == 'workflow_dispatch' || - (github.event_name == 'issues' && contains(github.event.issue.labels.*.name, 'sync-plugin-docs')) + (github.event_name == 'issues' && contains(github.event.issue.labels.*.name, 'source:sync')) steps: - name: Parse issue inputs @@ -170,7 +170,7 @@ jobs: repo: context.repo.repo, issue_number: parseInt(issueNumber), state: 'closed', - labels: ['sync-plugin-docs', 'validation-failed'] + labels: ['source:sync', 'validation-failed'] }); } @@ -418,7 +418,7 @@ jobs: repo: context.repo.repo, issue_number: ${{ steps.inputs.outputs.issue_number }}, state: 'closed', - labels: ['sync-plugin-docs', 'completed'] + labels: ['source:sync', 'completed'] }); - name: Report failure diff --git a/.mcp.json b/.mcp.json index f600dfa67..f18a0f326 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,20 +1,33 @@ { "$schema": "https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/refs/heads/main/schema/2025-06-18/schema.json", - "description": "InfluxData documentation assistance via MCP server - Node.js execution", + "description": "InfluxData documentation assistance via MCP servers", "mcpServers": { + "influxdb-docs": { + "comment": "Hosted InfluxDB documentation search. Uses API key auth (set INFLUXDATA_DOCS_KAPA_API_KEY env var). Get your key from the Kapa dashboard. Rate limits: 60 req/min.", + "type": "sse", + "url": "https://influxdb-docs.mcp.kapa.ai", + "headers": { + "Authorization": "Bearer ${INFLUXDATA_DOCS_KAPA_API_KEY}" + } + }, + "influxdb-docs-oauth": { + "comment": "Hosted InfluxDB documentation search (OAuth). No API key needed--authenticates via Google or GitHub OAuth on first use. Rate limits: 40 req/hr, 200 req/day.", + "type": "sse", + "url": "https://influxdb-docs.mcp.kapa.ai" + }, "influxdata": { - "comment": "Use Node to run Docs MCP. To install and setup, see https://github.com/influxdata/docs-mcp-server", + "comment": "Local Docs MCP server (optional). To install and setup, see https://github.com/influxdata/docs-mcp-server. NOTE: uses deprecated endpoints--pending update.", "type": "stdio", "command": "node", "args": [ "${DOCS_MCP_SERVER_PATH}/dist/index.js" ], "env": { - "DOCS_API_KEY_FILE": "${DOCS_API_KEY_FILE:-$HOME/.env.docs-kapa-api-key}", - "DOCS_MODE": "external-only", - "MCP_LOG_LEVEL": "${MCP_LOG_LEVEL:-info}", + "INFLUXDATA_DOCS_API_KEY_FILE": "${INFLUXDATA_DOCS_API_KEY_FILE:-$HOME/.env.docs-kapa-api-key}", + "INFLUXDATA_DOCS_MODE": "external-only", + "INFLUXDATA_DOCS_LOG_LEVEL": "${INFLUXDATA_DOCS_LOG_LEVEL:-info}", "NODE_ENV": "${NODE_ENV:-production}" } } } -} \ No newline at end of file +} diff --git a/AGENTS.md b/AGENTS.md index ecc293d22..bd27e9efa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,33 +1,21 @@ # InfluxData Documentation (docs-v2) -> **For general AI assistants (Claude, ChatGPT, Gemini, etc.)** -> -> This guide provides comprehensive instructions for AI assistants helping with the InfluxData documentation repository. It focuses on content creation, writing workflows, and style guidelines. -> +> **Shared project guidelines for all AI assistants** +> > **Other instruction resources**: -> - [.github/copilot-instructions.md](.github/copilot-instructions.md) - For GitHub Copilot (focused on coding and automation) -> - [CLAUDE.md](CLAUDE.md) - For Claude with MCP (minimal pointer) +> - [.github/copilot-instructions.md](.github/copilot-instructions.md) - GitHub Copilot (CLI tools, workflows, repo structure) +> - [CLAUDE.md](CLAUDE.md) - Claude with MCP (pointer file) > - [.claude/](.claude/) - Claude MCP configuration (commands, agents, skills) > - [.github/instructions/](.github/instructions/) - File pattern-specific instructions -## Project Overview +## Commands -This repository powers [docs.influxdata.com](https://docs.influxdata.com), a Hugo-based static documentation site covering InfluxDB 3, InfluxDB v2/v1, Telegraf, and related products. - -**Key Characteristics:** -- **Scale**: 5,359+ pages -- **Build time**: ~75 seconds (NEVER cancel Hugo builds) -- **Tech stack**: Hugo, Node.js, Docker, Vale, Pytest, Cypress -- **Test time**: 15-45 minutes for full code block tests - -## Quick Commands - -| Task | Command | Time | -|------|---------|------| -| Install dependencies | `CYPRESS_INSTALL_BINARY=0 yarn install` | ~4s | -| Build site | `npx hugo --quiet` | ~75s | -| Dev server | `npx hugo server` | ~92s | -| Test code blocks | `yarn test:codeblocks:all` | 15-45m | +| Task | Command | Notes | +|------|---------|-------| +| Install | `CYPRESS_INSTALL_BINARY=0 yarn install` | ~4s | +| Build | `npx hugo --quiet` | ~75s — **NEVER CANCEL** | +| Dev server | `npx hugo server` | ~92s, port 1313 | +| Test code blocks | `yarn test:codeblocks:all` | 15-45m — **NEVER CANCEL** | | Lint | `yarn lint` | ~1m | ## Repository Structure @@ -43,7 +31,7 @@ docs-v2/ │ └── example.md # Shortcode testing playground ├── layouts/ # Hugo templates and shortcodes ├── assets/ # JS, CSS, TypeScript -├── api-docs/ # OpenAPI specifications +├── api-docs/ # InfluxDB OpenAPI specifications, API reference documentation generation scripts ├── data/ # YAML/JSON data files ├── public/ # Build output (gitignored, ~529MB) └── .github/ @@ -52,16 +40,16 @@ docs-v2/ **Content Paths**: See [copilot-instructions.md](.github/copilot-instructions.md#content-organization) +## Documentation MCP Server + +A hosted MCP server provides semantic search over all InfluxDB documentation. +Use it to verify technical accuracy, check API syntax, and find related docs. + +See the [InfluxDB documentation MCP server guide](https://docs.influxdata.com/influxdb3/core/admin/mcp-server/) for setup instructions. + ## Common Workflows -### Editing a page in your browser - -1. Navigate to the desired page on [docs.influxdata.com](https://docs.influxdata.com) -2. Click the "Edit this page" link at the bottom -3. Make changes in the GitHub web editor -4. Commit changes via a pull request - -### Creating/Editing Content Manually +### Creating/Editing Content **Frontmatter** (page metadata): ```yaml @@ -107,134 +95,83 @@ yarn test:links content/influxdb3/core/**/*.md **📖 Complete Reference**: [DOCS-TESTING.md](DOCS-TESTING.md) -### Committing Changes -**Commit Message Format**: -``` -type(scope): description +## Constraints -Examples: -- fix(enterprise): correct Docker environment variable -- feat(influxdb3): add new plugin documentation -- docs(core): update configuration examples -``` +- **NEVER cancel** Hugo builds (~75s) or test runs (15-45m) — the site has 5,359+ pages +- Set timeouts: Hugo 180s+, tests 30m+ +- Use `python` not `py` for code block language identifiers (pytest won't collect `py` blocks) +- Shared content files (`content/shared/`) have no frontmatter — the consuming page provides it +- Product names and versions come from `data/products.yml` (single source of truth) +- Commit format: `type(scope): description` — see [DOCS-CONTRIBUTING.md](DOCS-CONTRIBUTING.md#commit-guidelines) +- Network-restricted environments: Cypress (`CYPRESS_INSTALL_BINARY=0`), Docker builds, and Alpine packages may fail -**Types**: `fix`, `feat`, `style`, `refactor`, `test`, `chore` +## Style Rules -**Scopes**: `enterprise`, `influxdb3`, `core`, `cloud`, `telegraf`, etc. +Follows [Google Developer Documentation Style Guide](https://developers.google.com/style) with these project-specific additions: -**Pre-commit hooks** run automatically (Vale, Prettier, tests). Skip with: -```bash -git commit -m "message" --no-verify -``` +- **Semantic line feeds** — one sentence per line (better diffs) +- **No h1 in content** — `title` frontmatter auto-generates h1 +- Active voice, present tense, second person +- Long options in CLI examples (`--output` not `-o`) +- Code blocks within 80 characters -**📖 Complete Reference**: [DOCS-CONTRIBUTING.md](DOCS-CONTRIBUTING.md#commit-guidelines) +## Content Structure -## Key Patterns +**Required frontmatter**: `title`, `description`, `menu`, `weight` +— see [DOCS-FRONTMATTER.md](DOCS-FRONTMATTER.md) -### Content Organization +**Shared content**: `source: /shared/path/to/content.md` +— shared files use `{{% show-in %}}` / `{{% hide-in %}}` for product-specific content -- **Product versions**: Managed in `/data/products.yml` -- **Semantic line feeds**: One sentence per line for better diffs -- **Heading hierarchy**: Use h2-h6 only (h1 auto-generated from frontmatter) -- **Image naming**: `project/version-context-description.png` +**Shortcodes**: Callouts use `> [!Note]` / `> [!Warning]` syntax +— see [DOCS-SHORTCODES.md](DOCS-SHORTCODES.md) and [content/example.md](content/example.md) -### Code Examples +## Product Content Paths -**Testable code blocks** (pytest): -```python -print("Hello, world!") -``` +Canonical paths from `data/products.yml`: - +| Product | Content Path | +|---------|-------------| +| InfluxDB 3 Core | `content/influxdb3/core/` | +| InfluxDB 3 Enterprise | `content/influxdb3/enterprise/` | +| InfluxDB 3 Explorer | `content/influxdb3/explorer/` | +| InfluxDB Cloud Serverless | `content/influxdb3/cloud-serverless/` | +| InfluxDB Cloud Dedicated | `content/influxdb3/cloud-dedicated/` | +| InfluxDB Clustered | `content/influxdb3/clustered/` | +| InfluxDB OSS v2 | `content/influxdb/v2/` | +| InfluxDB OSS v1 | `content/influxdb/v1/` | +| InfluxDB Cloud (TSM) | `content/influxdb/cloud/` | +| InfluxDB Enterprise v1 | `content/enterprise_influxdb/` | +| Telegraf | `content/telegraf/` | +| Chronograf | `content/chronograf/` | +| Kapacitor | `content/kapacitor/` | +| Flux | `content/flux/` | +| Shared content | `content/shared/` | -``` -Hello, world! -``` +## Doc Review Pipeline -**Language identifiers**: Use `python` not `py`, `bash` not `sh` (for pytest collection) +Automated PR review for documentation changes. +See [.github/LABEL_GUIDE.md](.github/LABEL_GUIDE.md) for the label taxonomy. -### API Documentation +| Resource | Path | +|----------|------| +| Label guide | [.github/LABEL_GUIDE.md](.github/LABEL_GUIDE.md) | +| Triage agent | [.claude/agents/doc-triage-agent.md](.claude/agents/doc-triage-agent.md) | +| Content review instructions | [.github/instructions/content-review.instructions.md](.github/instructions/content-review.instructions.md) | +| Review agent (local) | [.claude/agents/doc-review-agent.md](.claude/agents/doc-review-agent.md) | +| Auto-label workflow | [.github/workflows/auto-label.yml](.github/workflows/auto-label.yml) | +| Doc review workflow | [.github/workflows/doc-review.yml](.github/workflows/doc-review.yml) | -- **Location**: `/api-docs/` directory -- **Format**: OpenAPI 3.0 YAML -- **Generation**: Uses Redoc + custom processing -- **📖 Workflow**: [api-docs/README.md](api-docs/README.md) - -### JavaScript/TypeScript - -- **Entry point**: `assets/js/main.js` -- **Pattern**: Component-based with `data-component` attributes -- **Debugging**: Source maps or debug helpers available -- **📖 Details**: [DOCS-CONTRIBUTING.md](DOCS-CONTRIBUTING.md#javascript-in-the-documentation-ui) - -## Important Constraints - -### Performance -- **NEVER cancel Hugo builds** - they take ~75s normally -- **NEVER cancel test runs** - code block tests take 15-45 minutes -- **Set timeouts**: Hugo (180s+), tests (30+ minutes) - -### Style Guidelines -- Use Google Developer Documentation style -- Active voice, present tense, second person for instructions -- No emojis unless explicitly requested -- Use long options in CLI examples (`--option` vs `-o`) -- Format code blocks within 80 characters - -### Network Restrictions -Some operations may fail in restricted environments: -- Docker builds requiring external repos -- `docker compose up local-dev` (Alpine packages) -- Cypress installation (use `CYPRESS_INSTALL_BINARY=0`) - -## Documentation References +## Reference | Document | Purpose | |----------|---------| -| [DOCS-CONTRIBUTING.md](DOCS-CONTRIBUTING.md) | Contribution workflow, style guidelines | -| [DOCS-TESTING.md](DOCS-TESTING.md) | Testing procedures (code blocks, links, linting) | +| [DOCS-CONTRIBUTING.md](DOCS-CONTRIBUTING.md) | Style guidelines, commit format, contribution workflow | +| [DOCS-TESTING.md](DOCS-TESTING.md) | Code block testing, link validation, Vale linting | | [DOCS-SHORTCODES.md](DOCS-SHORTCODES.md) | Complete shortcode reference | | [DOCS-FRONTMATTER.md](DOCS-FRONTMATTER.md) | Complete frontmatter field reference | -| [.github/copilot-instructions.md](.github/copilot-instructions.md) | Primary AI assistant instructions | | [api-docs/README.md](api-docs/README.md) | API documentation workflow | -| [content/example.md](content/example.md) | Live shortcode examples for testing | - -## Specialized Topics - -### Working with Specific Products - -| Product | Content Path | Special Notes | -|---------|-------------|---------------| -| InfluxDB 3 Core | `/content/influxdb3/core/` | Latest architecture | -| InfluxDB 3 Enterprise | `/content/influxdb3/enterprise/` | Core + licensed features, clustered | -| InfluxDB Cloud Dedicated | `/content/influxdb3/cloud-dedicated/`, `/content/influxdb3/cloud-serverless/` | Managed and distributed | -| InfluxDB Clustered | `/content/influxdb3/clustered/` | Self-managed and distributed | -| InfluxDB Cloud | `/content/influxdb/cloud/` | Legacy but active | -| InfluxDB v2 | `/content/influxdb/v2/` | Legacy but active | -| InfluxDB Enterprise v1 | `/content/enterprise_influxdb/v1/` | Legacy but active enterprise, clustered | - -### Advanced Tasks - -- **Vale configuration**: `.ci/vale/styles/` for custom rules -- **Link checking**: Uses custom `link-checker` binary -- **Docker testing**: `compose.yaml` defines test services -- **Lefthook**: Git hooks configuration in `lefthook.yml` - -## Troubleshooting - -| Issue | Solution | -|-------|----------| -| Pytest collected 0 items | Use `python` not `py` for code block language | -| Hugo build errors | Check `/config/_default/` configuration | -| Link validation slow | Test specific files: `yarn test:links content/file.md` | -| Vale errors | Check `.ci/vale/styles/config/vocabularies` | - -## Critical Reminders - -1. **Be a critical thinking partner** - Challenge assumptions, identify issues -2. **Test before committing** - Run relevant tests locally -3. **Reference, don't duplicate** - Link to detailed docs instead of copying -4. **Respect build times** - Don't cancel long-running operations -5. **Follow conventions** - Use established patterns for consistency - +| [content/example.md](content/example.md) | Live shortcode examples | +| [.github/copilot-instructions.md](.github/copilot-instructions.md) | CLI tools, repo structure, workflows | +| [.github/LABEL_GUIDE.md](.github/LABEL_GUIDE.md) | Label taxonomy and review pipeline | diff --git a/CLAUDE.md b/CLAUDE.md index fe99fa453..dc8350d2b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,12 +6,23 @@ > > **Full instruction resources**: > - [.github/copilot-instructions.md](.github/copilot-instructions.md) - For GitHub Copilot (technical setup, automation) -> - [AGENTS.md](AGENTS.md) - For general AI assistants (content creation, workflows, style guidelines) +> - [AGENTS.md](AGENTS.md) - Shared project guidelines (style, constraints, content structure) +> - [.github/LABEL_GUIDE.md](.github/LABEL_GUIDE.md) - Label taxonomy and pipeline usage > - [.claude/](.claude/) - Claude MCP configuration directory with: > - Custom commands in `.claude/commands/` > - Specialized agents in `.claude/agents/` > - Custom skills in `.claude/skills/` +## Documentation MCP server + +This repo includes [`.mcp.json`](.mcp.json) with a hosted InfluxDB documentation search server. +Use it to verify technical accuracy, check API syntax, and find related docs. + +- **`influxdb-docs`** — API key auth. Set `INFLUXDATA_DOCS_KAPA_API_KEY` env var before launching Claude Code. +- **`influxdb-docs-oauth`** — OAuth fallback. No setup needed. + +See [content-editing skill](.claude/skills/content-editing/SKILL.md#part-4-fact-checking-with-the-documentation-mcp-server) for usage details. + ## Purpose and scope Claude should help document InfluxData products by creating clear, accurate technical content with proper code examples, frontmatter, and formatting. diff --git a/api-docs/generate-api-docs.sh b/api-docs/generate-api-docs.sh index 1e7820a7e..f603bb2af 100755 --- a/api-docs/generate-api-docs.sh +++ b/api-docs/generate-api-docs.sh @@ -70,7 +70,7 @@ function generateHtml { local specbundle=redoc-static_index.html # Define the temporary file for the Hugo template and Redoc HTML. local tmpfile="${productVersion}-${api}_index.tmp" - + echo "Bundling $specPath" # Use npx to install and run the specified version of redoc-cli. @@ -83,9 +83,9 @@ function generateHtml { --title="$title" \ --options.sortPropsAlphabetically \ --options.menuToggle \ - --options.hideDownloadButton \ --options.hideHostname \ --options.noAutoAuth \ + --options.hideDownloadButton \ --output=$specbundle \ --templateOptions.description="$shortDescription" \ --templateOptions.product="$productVersion" \ diff --git a/api-docs/influxdb3/core/.config.yml b/api-docs/influxdb3/core/.config.yml index 14792e219..d492b29ed 100644 --- a/api-docs/influxdb3/core/.config.yml +++ b/api-docs/influxdb3/core/.config.yml @@ -7,7 +7,7 @@ x-influxdata-product-name: InfluxDB 3 Core apis: v3@3: - root: v3/ref.yml + root: v3/influxdb3-core-openapi.yaml x-influxdata-docs-aliases: - /influxdb3/core/api/ - /influxdb3/core/api/v1/ diff --git a/api-docs/influxdb3/core/v3/content/info.yml b/api-docs/influxdb3/core/v3/content/info.yml index 34e55186e..107c08b13 100644 --- a/api-docs/influxdb3/core/v3/content/info.yml +++ b/api-docs/influxdb3/core/v3/content/info.yml @@ -21,10 +21,7 @@ description: | - `/`: Compatibility endpoints for InfluxDB v1 workloads and clients - `/api/v2/write`: Compatibility endpoint for InfluxDB v2 workloads and clients - + [Download the OpenAPI specification](/openapi/influxdb3-core-openapi.yaml) license: name: MIT url: 'https://opensource.org/licenses/MIT' diff --git a/api-docs/influxdb3/enterprise/v3/ref.yml b/api-docs/influxdb3/core/v3/influxdb3-core-openapi.yaml similarity index 77% rename from api-docs/influxdb3/enterprise/v3/ref.yml rename to api-docs/influxdb3/core/v3/influxdb3-core-openapi.yaml index 8a813ac3e..f41334147 100644 --- a/api-docs/influxdb3/enterprise/v3/ref.yml +++ b/api-docs/influxdb3/core/v3/influxdb3-core-openapi.yaml @@ -1,27 +1,24 @@ openapi: 3.0.3 info: - title: InfluxDB 3 Enterprise API Service + title: InfluxDB 3 Core API Service description: | - The InfluxDB HTTP API for InfluxDB 3 Enterprise provides a programmatic interface for - interacting with InfluxDB 3 Enterprise databases and resources. + The InfluxDB HTTP API for InfluxDB 3 Core provides a programmatic interface for + interacting with InfluxDB 3 Core databases and resources. Use this API to: - - Write data to InfluxDB 3 Enterprise databases + - Write data to InfluxDB 3 Core databases - Query data using SQL or InfluxQL - Process data using Processing engine plugins - Manage databases, tables, and Processing engine triggers - Perform administrative tasks and access system information The API includes endpoints under the following paths: - - `/api/v3`: InfluxDB 3 Enterprise native endpoints + - `/api/v3`: InfluxDB 3 Core native endpoints - `/`: Compatibility endpoints for InfluxDB v1 workloads and clients - `/api/v2/write`: Compatibility endpoint for InfluxDB v2 workloads and clients - - version: '3.7.0' + [Download the OpenAPI specification](/openapi/influxdb3-core-openapi.yaml) + version: v3.8.0 license: name: MIT url: https://opensource.org/licenses/MIT @@ -29,15 +26,16 @@ info: name: InfluxData url: https://www.influxdata.com email: support@influxdata.com + x-source-hash: sha256:1259b96096eab6c8dbf3f76c974924f124e9b3e08eedc6b0c9a66d3108857c52 servers: - url: https://{baseurl} - description: InfluxDB 3 Enterprise API URL + description: InfluxDB 3 Core API URL variables: baseurl: enum: - localhost:8181 default: localhost:8181 - description: InfluxDB 3 Enterprise URL + description: InfluxDB 3 Core URL security: - BearerAuthentication: [] - TokenAuthentication: [] @@ -56,8 +54,13 @@ tags: | [Querystring authentication](#section/Authentication/QuerystringAuthentication) | v1 endpoints | x-traitTag: true + x-related: + - title: Authenticate v1 API requests + href: /influxdb3/core/guides/api-compatibility/v1/ + - title: Manage tokens + href: /influxdb3/core/admin/tokens/ - name: Cache data - description: | + description: |- Manage the in-memory cache. #### Distinct Value Cache @@ -84,76 +87,126 @@ tags: what fields to cache, what tags to use to identify each series, and the number of values to cache for each unique series. An LVC is associated with a table, which can have multiple LVCs. - - #### Related guides - - - [Manage the Distinct Value Cache](/influxdb3/enterprise/admin/distinct-value-cache/) - - [Manage the Last Value Cache](/influxdb3/enterprise/admin/last-value-cache/) + x-related: + - title: Manage the Distinct Value Cache + href: /influxdb3/core/admin/distinct-value-cache/ + - title: Manage the Last Value Cache + href: /influxdb3/core/admin/last-value-cache/ - name: Compatibility endpoints - description: | + description: > InfluxDB 3 provides compatibility endpoints for InfluxDB 1.x and InfluxDB 2.x workloads and clients. + ### Write data using v1- or v2-compatible endpoints + - [`/api/v2/write` endpoint](#operation/PostV2Write) for InfluxDB v2 clients and when you bring existing InfluxDB v2 write workloads to InfluxDB 3. - - [`/write` endpoint](#operation/PostV1Write) for InfluxDB v1 clients and when you bring existing InfluxDB v1 write workloads to InfluxDB 3. + - [`/write` endpoint](#operation/PostV1Write) for InfluxDB v1 clients and when you bring existing InfluxDB v1 + write workloads to InfluxDB 3. + For new workloads, use the [`/api/v3/write_lp` endpoint](#operation/PostWriteLP). + All endpoints accept the same line protocol format. + ### Query data - Use the HTTP [`/query`](#operation/GetV1ExecuteQuery) endpoint for InfluxDB v1 clients and v1 query workloads using InfluxQL. + + Use the HTTP [`/query`](#operation/GetV1ExecuteQuery) endpoint for InfluxDB v1 clients and v1 query workloads + using InfluxQL. + For new workloads, use one of the following: + - HTTP [`/api/v3/query_sql` endpoint](#operation/GetExecuteQuerySQL) for new query workloads using SQL. - - HTTP [`/api/v3/query_influxql` endpoint](#operation/GetExecuteInfluxQLQuery) for new query workloads using InfluxQL. - - Flight SQL and InfluxDB 3 _Flight+gRPC_ APIs for querying with SQL or InfluxQL. For more information about using Flight APIs, see [InfluxDB 3 client libraries](https://github.com/InfluxCommunity?q=influxdb3&type=public&language=&sort=). + + - HTTP [`/api/v3/query_influxql` endpoint](#operation/GetExecuteInfluxQLQuery) for new query workloads using + InfluxQL. + + - Flight SQL and InfluxDB 3 _Flight+gRPC_ APIs for querying with SQL or InfluxQL. For more information about using + Flight APIs, see [InfluxDB 3 client + libraries](https://github.com/InfluxCommunity?q=influxdb3&type=public&language=&sort=). + ### Server information - Server information endpoints such as `/health` and `metrics` are compatible with InfluxDB 1.x and InfluxDB 2.x clients. + + Server information endpoints such as `/health` and `metrics` are compatible with InfluxDB 1.x and InfluxDB 2.x + clients. + x-related: + - title: Use compatibility APIs to write data + href: /influxdb3/core/write-data/http-api/compatibility-apis/ - name: Database description: Manage databases - - description: | + - description: > Most InfluxDB API endpoints require parameters in the request--for example, specifying the database to use. + ### Common parameters + The following table shows common parameters used by many InfluxDB API endpoints. + Many endpoints may require other parameters in the query string or in the + request body that perform functions specific to those endpoints. + | Query parameter | Value type | Description | + |:------------------------ |:--------------------- |:-------------------------------------------| + | `db` | string | The database name | + InfluxDB HTTP API endpoints use standard HTTP request and response headers. + The following table shows common headers used by many InfluxDB API endpoints. + Some endpoints may use other headers that perform functions more specific to those endpoints--for example, - the write endpoints accept the `Content-Encoding` header to indicate that line protocol is compressed in the request body. + + the write endpoints accept the `Content-Encoding` header to indicate that line protocol is compressed in the + request body. + | Header | Value type | Description | + |:------------------------ |:--------------------- |:-------------------------------------------| + | `Accept` | string | The content type that the client can understand. | + | `Authorization` | string | The authorization scheme and credential. | + | `Content-Length` | integer | The size of the entity-body, in bytes. | + | `Content-Type` | string | The format of the data in the request body. | name: Headers and parameters x-traitTag: true - name: Processing engine - description: | + description: > Manage Processing engine triggers, test plugins, and send requests to trigger On Request plugins. - InfluxDB 3 Enterprise provides the InfluxDB 3 processing engine, an embedded Python VM that can dynamically load and trigger Python plugins in response to events in your database. + + InfluxDB 3 Core provides the InfluxDB 3 processing engine, an embedded Python VM that can dynamically load and + trigger Python plugins in response to events in your database. + Use Processing engine plugins and triggers to run code and perform tasks for different database events. - To get started with the processing engine, see the [Processing engine and Python plugins](/influxdb3/enterprise/processing-engine/) guide. + + To get started with the processing engine, see the [Processing engine and Python + plugins](/influxdb3/core/processing-engine/) guide. + x-related: + - title: Processing engine and Python plugins + href: /influxdb3/core/plugins/ - name: Query data description: Query data using SQL or InfluxQL + x-related: + - title: Use the InfluxDB v1 HTTP query API and InfluxQL to query data + href: /influxdb3/core/query-data/execute-queries/influxdb-v1-api/ - name: Quick start description: | 1. [Create an admin token](#section/Authentication) to authorize API requests. @@ -195,7 +248,7 @@ tags: {"room":"Living room","temp":71.5,"time":"2025-02-25T20:19:34.984098"} ``` - For more information about using InfluxDB 3 Enterprise, see the [Get started](/influxdb3/enterprise/get-started/) guide. + For more information about using InfluxDB 3 Core, see the [Get started](/influxdb3/core/get-started/) guide. x-traitTag: true - name: Server information description: Retrieve server metrics, status, and version information @@ -219,157 +272,79 @@ tags: | **Milliseconds** | ✅ `ms` | ✅ `ms` | ✅ `millisecond` | | **Microseconds** | ✅ `u` or `µ` | ✅ `us` | ✅ `microsecond` | | **Nanoseconds** | ✅ `ns` | ✅ `ns` | ✅ `nanosecond` | - | **Minutes** | ✅ `m` | ❌ No | ❌ No | - | **Hours** | ✅ `h` | ❌ No | ❌ No | | **Default** | Nanosecond | Nanosecond | **Auto** (guessed) | All timestamps are stored internally as nanoseconds. paths: - /write: - post: - operationId: PostV1Write - summary: Write line protocol (v1-compatible) + /api/v1/health: + get: + operationId: GetHealthV1 + summary: Health check (v1) description: | - Writes line protocol to the specified database. + Checks the status of the service. - This endpoint provides backward compatibility for InfluxDB 1.x write workloads using tools such as InfluxDB 1.x client libraries, the Telegraf `outputs.influxdb` output plugin, or third-party tools. + Returns `OK` if the service is running. This endpoint does not return version information. + Use the [`/ping`](#operation/GetPing) endpoint to retrieve version details. - Use this endpoint to send data in [line protocol](https://docs.influxdata.com/influxdb3/enterprise/reference/syntax/line-protocol/) format to InfluxDB. - Use query parameters to specify options for writing data. - - #### Related - - - [Use compatibility APIs to write data](/influxdb3/enterprise/write-data/http-api/compatibility-apis/) - parameters: - - $ref: '#/components/parameters/dbWriteParam' - - $ref: '#/components/parameters/compatibilityPrecisionParam' - - $ref: '#/components/parameters/v1UsernameParam' - - $ref: '#/components/parameters/v1PasswordParam' - - name: rp - in: query - required: false - schema: - type: string - description: | - Retention policy name. Honored but discouraged. InfluxDB 3 doesn't use retention policies. - - name: consistency - in: query - required: false - schema: - type: string - description: | - Write consistency level. Ignored by InfluxDB 3. Provided for compatibility with InfluxDB 1.x clients. - - name: Authorization - in: header - required: false - schema: - type: string - description: | - Authorization header for token-based authentication. - Supported schemes: - - `Bearer AUTH_TOKEN` - OAuth bearer token scheme - - `Token AUTH_TOKEN` - InfluxDB v2 token scheme - - `Basic ` - Basic authentication (username is ignored) - - name: Content-Type - in: header - description: | - The content type of the request payload. - schema: - $ref: '#/components/schemas/LineProtocol' - required: false - - name: Accept - in: header - description: | - The content type that the client can understand. - Writes only return a response body if they fail (partially or completely)--for example, - due to a syntax problem or type mismatch. - schema: - type: string - default: application/json - enum: - - application/json - required: false - - $ref: '#/components/parameters/ContentEncoding' - - $ref: '#/components/parameters/ContentLength' - requestBody: - $ref: '#/components/requestBodies/lineProtocolRequestBody' + > **Note**: This endpoint requires authentication by default in InfluxDB 3 Core. responses: - '204': - description: Success ("No Content"). All data in the batch is written and queryable. - headers: - cluster-uuid: - $ref: '#/components/headers/ClusterUUID' - '400': - description: | - Bad request. Some (a _partial write_) or all of the data from the batch was rejected and not written. - If a partial write occurred, then some points from the batch are written and queryable. - - The response body: - - indicates if a partial write occurred or all data was rejected. - - contains details about the [rejected points](/influxdb3/enterprise/write-data/troubleshoot/#troubleshoot-rejected-points), up to 100 points. + "200": + description: Service is running. Returns `OK`. content: - application/json: - examples: - rejectedAllPoints: - summary: Rejected all points in the batch - value: | - { - "error": "write of line protocol failed", - "data": [ - { - "original_line": "dquote> home,room=Kitchen temp=hi", - "line_number": 2, - "error_message": "No fields were provided" - } - ] - } - partialWriteErrorWithRejectedPoints: - summary: Partial write rejected some points in the batch - value: | - { - "error": "partial write of line protocol occurred", - "data": [ - { - "original_line": "dquote> home,room=Kitchen temp=hi", - "line_number": 2, - "error_message": "No fields were provided" - } - ] - } - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '413': - description: Request entity too large. + text/plain: + schema: + type: string + example: OK + "401": + description: Unauthorized. Authentication is required. + "500": + description: Service is unavailable. tags: + - Server information - Compatibility endpoints - - Write data - x-influxdata-guides: - - title: Use compatibility APIs to write data - href: /influxdb3/enterprise/write-data/http-api/compatibility-apis/ /api/v2/write: post: operationId: PostV2Write + responses: + "204": + description: Success ("No Content"). All data in the batch is written and queryable. + headers: + cluster-uuid: + $ref: "#/components/headers/ClusterUUID" + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "413": + description: Request entity too large. summary: Write line protocol (v2-compatible) - description: | + description: > Writes line protocol to the specified database. - This endpoint provides backward compatibility for InfluxDB 2.x write workloads using tools such as InfluxDB 2.x client libraries, the Telegraf `outputs.influxdb_v2` output plugin, or third-party tools. - Use this endpoint to send data in [line protocol](/influxdb3/enterprise/reference/syntax/line-protocol/) format to InfluxDB. + This endpoint provides backward compatibility for InfluxDB 2.x write workloads using tools such as InfluxDB 2.x + client libraries, the Telegraf `outputs.influxdb_v2` output plugin, or third-party tools. + + + Use this endpoint to send data in [line protocol](/influxdb3/core/reference/syntax/line-protocol/) format to + InfluxDB. + Use query parameters to specify options for writing data. + #### Related - - [Use compatibility APIs to write data](/influxdb3/enterprise/write-data/http-api/compatibility-apis/) + + - [Use compatibility APIs to write data](/influxdb3/core/write-data/http-api/compatibility-apis/) parameters: - name: Content-Type in: header description: | The content type of the request payload. schema: - $ref: '#/components/schemas/LineProtocol' + $ref: "#/components/schemas/LineProtocol" required: false - description: | The compression applied to the line protocol in the request payload. @@ -404,750 +379,33 @@ paths: enum: - application/json type: string - - name: db + - name: bucket in: query required: true schema: type: string - description: | + description: |- A database name. InfluxDB creates the database if it doesn't already exist, and then writes all points in the batch to the database. + + This parameter is named `bucket` for compatibility with InfluxDB v2 client libraries. - name: accept_partial in: query required: false schema: - $ref: '#/components/schemas/AcceptPartial' - - $ref: '#/components/parameters/compatibilityPrecisionParam' + $ref: "#/components/schemas/AcceptPartial" + - $ref: "#/components/parameters/compatibilityPrecisionParam" requestBody: - $ref: '#/components/requestBodies/lineProtocolRequestBody' - responses: - '204': - description: Success ("No Content"). All data in the batch is written and queryable. - headers: - cluster-uuid: - $ref: '#/components/headers/ClusterUUID' - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '413': - description: Request entity too large. + $ref: "#/components/requestBodies/lineProtocolRequestBody" tags: - Compatibility endpoints - Write data - x-influxdata-guides: - - title: Use compatibility APIs to write data - href: /influxdb3/enterprise/write-data/http-api/compatibility-apis/ - /api/v3/write_lp: - post: - operationId: PostWriteLP - summary: Write line protocol - description: | - Writes line protocol to the specified database. - - This is the native InfluxDB 3 Enterprise write endpoint that provides enhanced control - over write behavior with advanced parameters for high-performance and fault-tolerant operations. - - Use this endpoint to send data in [line protocol](/influxdb3/enterprise/reference/syntax/line-protocol/) format to InfluxDB. - Use query parameters to specify options for writing data. - - #### Features - - - **Partial writes**: Use `accept_partial=true` to allow partial success when some lines in a batch fail - - **Asynchronous writes**: Use `no_sync=true` to skip waiting for WAL synchronization, allowing faster response times but sacrificing durability guarantees - - **Flexible precision**: Automatic timestamp precision detection with `precision=auto` (default) - - #### Auto precision detection - - When you use `precision=auto` or omit the precision parameter, InfluxDB 3 automatically detects - the timestamp precision based on the magnitude of the timestamp value: - - - Timestamps < 5e9 → Second precision (multiplied by 1,000,000,000 to convert to nanoseconds) - - Timestamps < 5e12 → Millisecond precision (multiplied by 1,000,000) - - Timestamps < 5e15 → Microsecond precision (multiplied by 1,000) - - Larger timestamps → Nanosecond precision (no conversion needed) - - #### Related - - - [Use the InfluxDB v3 write_lp API to write data](/influxdb3/enterprise/write-data/http-api/v3-write-lp/) - parameters: - - $ref: '#/components/parameters/dbWriteParam' - - $ref: '#/components/parameters/accept_partial' - - $ref: '#/components/parameters/precisionParam' - - name: no_sync - in: query - schema: - $ref: '#/components/schemas/NoSync' - - name: Content-Type - in: header - description: | - The content type of the request payload. - schema: - $ref: '#/components/schemas/LineProtocol' - required: false - - name: Accept - in: header - description: | - The content type that the client can understand. - Writes only return a response body if they fail (partially or completely)--for example, - due to a syntax problem or type mismatch. - schema: - type: string - default: application/json - enum: - - application/json - required: false - - $ref: '#/components/parameters/ContentEncoding' - - $ref: '#/components/parameters/ContentLength' - requestBody: - $ref: '#/components/requestBodies/lineProtocolRequestBody' - responses: - '204': - description: Success ("No Content"). All data in the batch is written and queryable. - headers: - cluster-uuid: - $ref: '#/components/headers/ClusterUUID' - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '413': - description: Request entity too large. - '422': - description: Unprocessable entity. - x-codeSamples: - - label: cURL - Basic write - lang: Shell - source: | - curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors" \ - --header "Authorization: Bearer DATABASE_TOKEN" \ - --header "Content-Type: text/plain" \ - --data-raw "cpu,host=server01 usage=85.2 1638360000000000000" - - label: cURL - Write with millisecond precision - lang: Shell - source: | - curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors&precision=ms" \ - --header "Authorization: Bearer DATABASE_TOKEN" \ - --header "Content-Type: text/plain" \ - --data-raw "cpu,host=server01 usage=85.2 1638360000000" - - label: cURL - Asynchronous write with partial acceptance - lang: Shell - source: | - curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors&accept_partial=true&no_sync=true&precision=auto" \ - --header "Authorization: Bearer DATABASE_TOKEN" \ - --header "Content-Type: text/plain" \ - --data-raw "cpu,host=server01 usage=85.2 - memory,host=server01 used=4096" - - label: cURL - Multiple measurements with tags - lang: Shell - source: | - curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors&precision=ns" \ - --header "Authorization: Bearer DATABASE_TOKEN" \ - --header "Content-Type: text/plain" \ - --data-raw "cpu,host=server01,region=us-west usage=85.2,load=0.75 1638360000000000000 - memory,host=server01,region=us-west used=4096,free=12288 1638360000000000000 - disk,host=server01,region=us-west,device=/dev/sda1 used=50.5,free=49.5 1638360000000000000" - tags: - - Write data - /api/v3/query_sql: - get: - operationId: GetExecuteQuerySQL - summary: Execute SQL query - description: Executes an SQL query to retrieve data from the specified database. - parameters: - - $ref: '#/components/parameters/db' - - $ref: '#/components/parameters/querySqlParam' - - $ref: '#/components/parameters/format' - - $ref: '#/components/parameters/AcceptQueryHeader' - - $ref: '#/components/parameters/ContentType' - responses: - '200': - description: Success. The response body contains query results. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResponse' - example: - results: - - series: - - name: mytable - columns: - - time - - value - values: - - - '2024-02-02T12:00:00Z' - - 42 - text/csv: - schema: - type: string - application/vnd.apache.parquet: - schema: - type: string - application/jsonl: - schema: - type: string - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '404': - description: Database not found. - '405': - description: Method not allowed. - '422': - description: Unprocessable entity. - tags: - - Query data - post: - operationId: PostExecuteQuerySQL - summary: Execute SQL query - description: Executes an SQL query to retrieve data from the specified database. - parameters: - - $ref: '#/components/parameters/AcceptQueryHeader' - - $ref: '#/components/parameters/ContentType' - requestBody: - $ref: '#/components/requestBodies/queryRequestBody' - responses: - '200': - description: Success. The response body contains query results. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResponse' - text/csv: - schema: - type: string - application/vnd.apache.parquet: - schema: - type: string - application/jsonl: - schema: - type: string - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '404': - description: Database not found. - '405': - description: Method not allowed. - '422': - description: Unprocessable entity. - tags: - - Query data - /api/v3/query_influxql: - get: - operationId: GetExecuteInfluxQLQuery - summary: Execute InfluxQL query - description: Executes an InfluxQL query to retrieve data from the specified database. - parameters: - - $ref: '#/components/parameters/dbQueryParam' - - name: q - in: query - required: true - schema: - type: string - - name: format - in: query - required: false - schema: - type: string - - $ref: '#/components/parameters/AcceptQueryHeader' - responses: - '200': - description: Success. The response body contains query results. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResponse' - text/csv: - schema: - type: string - application/vnd.apache.parquet: - schema: - type: string - application/jsonl: - schema: - type: string - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '404': - description: Database not found. - '405': - description: Method not allowed. - '422': - description: Unprocessable entity. - tags: - - Query data - post: - operationId: PostExecuteQueryInfluxQL - summary: Execute InfluxQL query - description: Executes an InfluxQL query to retrieve data from the specified database. - parameters: - - $ref: '#/components/parameters/AcceptQueryHeader' - - $ref: '#/components/parameters/ContentType' - requestBody: - $ref: '#/components/requestBodies/queryRequestBody' - responses: - '200': - description: Success. The response body contains query results. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResponse' - text/csv: - schema: - type: string - application/vnd.apache.parquet: - schema: - type: string - application/jsonl: - schema: - type: string - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '404': - description: Database not found. - '405': - description: Method not allowed. - '422': - description: Unprocessable entity. - tags: - - Query data - /query: - get: - operationId: GetV1ExecuteQuery - summary: Execute InfluxQL query (v1-compatible) - description: | - Executes an InfluxQL query to retrieve data from the specified database. - - This endpoint is compatible with InfluxDB 1.x client libraries and third-party integrations such as Grafana. - Use query parameters to specify the database and the InfluxQL query. - - #### Related - - - [Use the InfluxDB v1 HTTP query API and InfluxQL to query data](/influxdb3/enterprise/query-data/execute-queries/influxdb-v1-api/) - parameters: - - name: Accept - in: header - schema: - type: string - default: application/json - enum: - - application/json - - application/csv - - text/csv - required: false - description: | - The content type that the client can understand. - - If `text/csv` is specified, the `Content-type` response header is `application/csv` and the response is formatted as CSV. - - Returns an error if the format is invalid or non-UTF8. - - in: query - name: chunked - description: | - If true, the response is divided into chunks of size `chunk_size`. - schema: - type: boolean - default: false - - in: query - name: chunk_size - description: | - The number of records that will go into a chunk. - This parameter is only used if `chunked=true`. - schema: - type: integer - default: 10000 - - in: query - name: db - description: The database to query. If not provided, the InfluxQL query string must specify the database. - schema: - type: string - format: InfluxQL - - in: query - name: pretty - description: | - If true, the JSON response is formatted in a human-readable format. - schema: - type: boolean - default: false - - in: query - name: q - description: The InfluxQL query string. - required: true - schema: - type: string - - name: epoch - description: | - Formats timestamps as [unix (epoch) timestamps](/influxdb3/enterprise/reference/glossary/#unix-timestamp) with the specified precision - instead of [RFC3339 timestamps](/influxdb3/enterprise/reference/glossary/#rfc3339-timestamp) with nanosecond precision. - in: query - schema: - $ref: '#/components/schemas/EpochCompatibility' - - $ref: '#/components/parameters/v1UsernameParam' - - $ref: '#/components/parameters/v1PasswordParam' - - name: rp - in: query - required: false - schema: - type: string - description: | - Retention policy name. Honored but discouraged. InfluxDB 3 doesn't use retention policies. - - name: Authorization - in: header - required: false - schema: - type: string - description: | - Authorization header for token-based authentication. - Supported schemes: - - `Bearer AUTH_TOKEN` - OAuth bearer token scheme - - `Token AUTH_TOKEN` - InfluxDB v2 token scheme - - `Basic ` - Basic authentication (username is ignored) - responses: - '200': - description: | - Success. The response body contains query results. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResponse' - application/csv: - schema: - type: string - headers: - Content-Type: - description: | - The content type of the response. - Default is `application/json`. - - If the `Accept` request header is `application/csv` or `text/csv`, the `Content-type` response header is `application/csv` - and the response is formatted as CSV. - schema: - type: string - default: application/json - enum: - - application/json - - application/csv - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '404': - description: Database not found. - '405': - description: Method not allowed. - '422': - description: Unprocessable entity. - tags: - - Query data - - Compatibility endpoints - x-influxdata-guides: - - title: Use the InfluxDB v1 HTTP query API and InfluxQL to query data - href: /influxdb3/enterprise/query-data/execute-queries/influxdb-v1-api/ - post: - operationId: PostExecuteV1Query - summary: Execute InfluxQL query (v1-compatible) - description: | - Executes an InfluxQL query to retrieve data from the specified database. - - #### Related - - - [Use the InfluxDB v1 HTTP query API and InfluxQL to query data](/influxdb3/enterprise/query-data/execute-queries/influxdb-v1-api/) - requestBody: - content: - application/json: - schema: - type: object - properties: - db: - type: string - description: The database to query. If not provided, the InfluxQL query string must specify the database. - q: - description: The InfluxQL query string. - type: string - chunked: - description: | - If true, the response is divided into chunks of size `chunk_size`. - type: boolean - chunk_size: - description: | - The number of records that will go into a chunk. - This parameter is only used if `chunked=true`. - type: integer - default: 10000 - epoch: - description: | - A unix timestamp precision. - - - `h` for hours - - `m` for minutes - - `s` for seconds - - `ms` for milliseconds - - `u` or `µ` for microseconds - - `ns` for nanoseconds - - Formats timestamps as [unix (epoch) timestamps](/influxdb3/enterprise/reference/glossary/#unix-timestamp) with the specified precision - instead of [RFC3339 timestamps](/influxdb3/enterprise/reference/glossary/#rfc3339-timestamp) with nanosecond precision. - enum: - - ns - - u - - µ - - ms - - s - - m - - h - type: string - pretty: - description: | - If true, the JSON response is formatted in a human-readable format. - type: boolean - required: - - q - parameters: - - name: Accept - in: header - schema: - type: string - default: application/json - enum: - - application/json - - application/csv - - text/csv - required: false - description: | - The content type that the client can understand. - - If `text/csv` is specified, the `Content-type` response header is `application/csv` and the response is formatted as CSV. - - Returns an error if the format is invalid or non-UTF8. - responses: - '200': - description: | - Success. The response body contains query results. - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResponse' - application/csv: - schema: - type: string - headers: - Content-Type: - description: | - The content type of the response. - Default is `application/json`. - - If the `Accept` request header is `application/csv` or `text/csv`, the `Content-type` response header is `application/csv` - and the response is formatted as CSV. - schema: - type: string - default: application/json - enum: - - application/json - - application/csv - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - '404': - description: Database not found. - '405': - description: Method not allowed. - '422': - description: Unprocessable entity. - tags: - - Query data - - Compatibility endpoints - x-influxdata-guides: - - title: Use the InfluxDB v1 HTTP query API and InfluxQL to query data - href: /influxdb3/enterprise/query-data/execute-queries/influxdb-v1-api/ - /health: - get: - operationId: GetHealth - summary: Health check - description: | - Checks the status of the service. - - Returns `OK` if the service is running. This endpoint does not return version information. - Use the [`/ping`](#operation/GetPing) endpoint to retrieve version details. - - > **Note**: This endpoint requires authentication by default in InfluxDB 3 Enterprise. - responses: - '200': - description: Service is running. Returns `OK`. - content: - text/plain: - schema: - type: string - example: OK - '401': - description: Unauthorized. Authentication is required. - '500': - description: Service is unavailable. - tags: - - Server information - /api/v1/health: - get: - operationId: GetHealthV1 - summary: Health check (v1) - description: Checks the status of the service. - responses: - '200': - description: Service is running. - '500': - description: Service is unavailable. - tags: - - Server information - - Compatibility endpoints - /ping: - get: - operationId: GetPing - tags: - - Server information - summary: Ping the server - description: | - Returns version information for the server. - - **Important**: Use a GET request. HEAD requests return `404 Not Found`. - - The response includes version information in both headers and the JSON body: - - - **Headers**: `x-influxdb-version` and `x-influxdb-build` - - **Body**: JSON object with `version`, `revision`, and `process_id` - - > **Note**: This endpoint requires authentication by default in InfluxDB 3 Enterprise. - responses: - '200': - description: Success. The response body contains server information. - headers: - x-influxdb-version: - description: The InfluxDB version number (for example, `3.8.0`). - schema: - type: string - example: '3.8.0' - x-influxdb-build: - description: The InfluxDB build type (`Core` or `Enterprise`). - schema: - type: string - example: Enterprise - content: - application/json: - schema: - type: object - properties: - version: - type: string - description: The InfluxDB version number. - example: '3.8.0' - revision: - type: string - description: The git revision hash for the build. - example: '83b589b883' - process_id: - type: string - description: A unique identifier for the server process. - example: 'b756d9e0-cecd-4f72-b6d0-19e2d4f8cbb7' - '401': - description: Unauthorized. Authentication is required. - '404': - description: | - Not Found. Returned for HEAD requests. - Use a GET request to retrieve version information. - /metrics: - get: - operationId: GetMetrics - summary: Metrics - description: Retrieves Prometheus-compatible server metrics. - responses: - '200': - description: Success. The response body contains Prometheus-compatible server metrics. - tags: - - Server information /api/v3/configure/database: - get: - operationId: GetConfigureDatabase - summary: List databases - description: Retrieves a list of databases. - parameters: - - $ref: '#/components/parameters/formatRequired' - - name: show_deleted - in: query - required: false - schema: - type: boolean - default: false - description: | - Include soft-deleted databases in the response. - By default, only active databases are returned. - responses: - '200': - description: Success. The response body contains the list of databases. - content: - application/json: - schema: - $ref: '#/components/schemas/ShowDatabasesResponse' - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Database not found. - tags: - - Database - post: - operationId: PostConfigureDatabase - summary: Create a database - description: Creates a new database in the system. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateDatabaseRequest' - responses: - '201': - description: Success. Database created. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '409': - description: Database already exists. - tags: - - Database delete: operationId: DeleteConfigureDatabase - summary: Delete a database - description: | - Soft deletes a database. - The database is scheduled for deletion and unavailable for querying. - Use the `hard_delete_at` parameter to schedule a hard deletion. - Use the `data_only` parameter to delete data while preserving the database schema and resources. parameters: - - $ref: '#/components/parameters/db' + - $ref: "#/components/parameters/db" - name: data_only in: query required: false @@ -1174,7 +432,7 @@ paths: schema: type: string format: date-time - description: | + description: |- Schedule the database for hard deletion at the specified time. If not provided, the database will be soft deleted. Use ISO 8601 date-time format (for example, "2025-12-31T23:59:59Z"). @@ -1183,13 +441,98 @@ paths: Deleting a database is a destructive action. Once a database is deleted, data stored in that database cannot be recovered. + + + Also accepts special string values: + - `now` — hard delete immediately + - `never` — soft delete only (default behavior) + - `default` — use the system default hard deletion time responses: - '200': + "200": description: Success. Database deleted. - '401': - $ref: '#/components/responses/Unauthorized' - '404': + "401": + $ref: "#/components/responses/Unauthorized" + "404": description: Database not found. + summary: Delete a database + description: | + Soft deletes a database. + The database is scheduled for deletion and unavailable for querying. + Use the `hard_delete_at` parameter to schedule a hard deletion. + Use the `data_only` parameter to delete data while preserving the database schema and resources. + tags: + - Database + get: + operationId: GetConfigureDatabase + responses: + "200": + description: Success. The response body contains the list of databases. + content: + application/json: + schema: + $ref: "#/components/schemas/ShowDatabasesResponse" + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + summary: List databases + description: Retrieves a list of databases. + parameters: + - $ref: "#/components/parameters/formatRequired" + - name: show_deleted + in: query + required: false + schema: + type: boolean + default: false + description: | + Include soft-deleted databases in the response. + By default, only active databases are returned. + tags: + - Database + post: + operationId: PostConfigureDatabase + responses: + "200": + description: Success. Database created. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "409": + description: Database already exists. + summary: Create a database + description: Creates a new database in the system. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateDatabaseRequest" + tags: + - Database + put: + operationId: update_database + responses: + "200": + description: Success. The database has been updated. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + summary: Update a database + description: | + Updates database configuration, such as retention period. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateDatabaseRequest" tags: - Database /api/v3/configure/database/retention_period: @@ -1199,188 +542,32 @@ paths: description: | Removes the retention period from a database, setting it to infinite retention. parameters: - - $ref: '#/components/parameters/db' + - $ref: "#/components/parameters/db" responses: - '204': + "204": description: Success. The database retention period has been removed. - '401': - $ref: '#/components/responses/Unauthorized' - '404': + "401": + $ref: "#/components/responses/Unauthorized" + "404": description: Database not found. tags: - Database - /api/v3/configure/table: - post: - operationId: PostConfigureTable - summary: Create a table - description: Creates a new table within a database. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateTableRequest' - responses: - '201': - description: Success. The table has been created. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Database not found. - tags: - - Table - delete: - operationId: DeleteConfigureTable - summary: Delete a table - description: | - Soft deletes a table. - The table is scheduled for deletion and unavailable for querying. - Use the `hard_delete_at` parameter to schedule a hard deletion. - Use the `data_only` parameter to delete data while preserving the table schema and resources. - - #### Deleting a table cannot be undone - - Deleting a table is a destructive action. - Once a table is deleted, data stored in that table cannot be recovered. - parameters: - - $ref: '#/components/parameters/db' - - name: table - in: query - required: true - schema: - type: string - - name: data_only - in: query - required: false - schema: - type: boolean - default: false - description: | - Delete only data while preserving the table schema and all associated resources - (last value caches, distinct value caches). - When `false` (default), the entire table is deleted. - - name: hard_delete_at - in: query - required: false - schema: - type: string - format: date-time - description: | - Schedule the table for hard deletion at the specified time. - If not provided, the table will be soft deleted. - Use ISO 8601 format (for example, "2025-12-31T23:59:59Z"). - responses: - '200': - description: Success (no content). The table has been deleted. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Table not found. - tags: - - Table - patch: - operationId: PatchConfigureTable - summary: Update a table - description: | - Updates table configuration, such as retention period. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateTableRequest' - responses: - '200': - description: Success. The table has been updated. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Table not found. - tags: - - Table - /api/v3/configure/database/{db}: - patch: - operationId: PatchConfigureDatabase - summary: Update a database - description: | - Updates database configuration, such as retention period. - parameters: - - name: db - in: path - required: true - schema: - type: string - description: The name of the database to update. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateDatabaseRequest' - responses: - '200': - description: Success. The database has been updated. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Database not found. - tags: - - Database - /api/v3/show/license: - get: - operationId: GetShowLicense - summary: Show license information - description: | - Retrieves information about the current InfluxDB 3 Enterprise license. - responses: - '200': - description: Success. The response body contains license information. - content: - application/json: - schema: - $ref: '#/components/schemas/LicenseResponse' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Access denied. - tags: - - Server information /api/v3/configure/distinct_cache: - post: - operationId: PostConfigureDistinctCache - summary: Create distinct cache - description: Creates a distinct cache for a table. - tags: - - Cache data - - Table - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/DistinctCacheCreateRequest' - responses: - '201': - description: Success. The distinct cache has been created. - '204': - description: Not created. A distinct cache with this configuration already exists. - '400': - description: | - Bad request. - - The server responds with status `400` if the request would overwrite an existing cache with a different configuration. delete: operationId: DeleteConfigureDistinctCache + responses: + "200": + description: Success. The distinct cache has been deleted. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Cache not found. summary: Delete distinct cache description: Deletes a distinct cache. parameters: - - $ref: '#/components/parameters/db' + - $ref: "#/components/parameters/db" - name: table in: query required: true @@ -1393,49 +580,50 @@ paths: schema: type: string description: The name of the distinct cache to delete. - responses: - '200': - description: Success. The distinct cache has been deleted. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Cache not found. tags: - Cache data - Table - /api/v3/configure/last_cache: post: - operationId: PostConfigureLastCache - summary: Create last cache - description: Creates a last cache for a table. + operationId: PostConfigureDistinctCache + responses: + "201": + description: Success. The distinct cache has been created. + "400": + description: > + Bad request. + + + The server responds with status `400` if the request would overwrite an existing cache with a different + configuration. + "409": + description: Conflict. A distinct cache with this configuration already exists. + summary: Create distinct cache + description: Creates a distinct cache for a table. requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/LastCacheCreateRequest' - responses: - '201': - description: Success. Last cache created. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Cache not found. - '409': - description: Cache already exists. + $ref: "#/components/schemas/DistinctCacheCreateRequest" tags: - Cache data - Table + /api/v3/configure/last_cache: delete: operationId: DeleteConfigureLastCache + responses: + "200": + description: Success. The last cache has been deleted. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Cache not found. summary: Delete last cache description: Deletes a last cache. parameters: - - $ref: '#/components/parameters/db' + - $ref: "#/components/parameters/db" - name: table in: query required: true @@ -1448,40 +636,142 @@ paths: schema: type: string description: The name of the last cache to delete. - responses: - '200': - description: Success. The last cache has been deleted. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Cache not found. tags: - Cache data - Table - /api/v3/configure/processing_engine_trigger: post: - operationId: PostConfigureProcessingEngineTrigger - summary: Create processing engine trigger - description: | - Creates a processing engine trigger with the specified plugin file and trigger specification. - - ### Related guides - - - [Processing engine and Python plugins](/influxdb3/enterprise/plugins/) + operationId: PostConfigureLastCache + responses: + "201": + description: Success. Last cache created. + "400": + description: Bad request. A cache with this name already exists or the request is malformed. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Cache not found. + summary: Create last cache + description: Creates a last cache for a table. requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/ProcessingEngineTriggerRequest' + $ref: "#/components/schemas/LastCacheCreateRequest" + tags: + - Cache data + - Table + /api/v3/configure/plugin_environment/install_packages: + post: + operationId: PostInstallPluginPackages + summary: Install plugin packages + description: |- + Installs the specified Python packages into the processing engine plugin environment. + + This endpoint is synchronous and blocks until the packages are installed. + parameters: + - $ref: "#/components/parameters/ContentType" + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + packages: + type: array + items: + type: string + description: | + A list of Python package names to install. + Can include version specifiers (e.g., "scipy==1.9.0"). + example: + - influxdb3-python + - scipy + - pandas==1.5.0 + - requests + required: + - packages + example: + packages: + - influxdb3-python + - scipy + - pandas==1.5.0 + - requests + responses: + "200": + description: Success. The packages are installed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + tags: + - Processing engine + /api/v3/configure/plugin_environment/install_requirements: + post: + operationId: PostInstallPluginRequirements + summary: Install plugin requirements + description: > + Installs requirements from a requirements file (also known as a "pip requirements file") into the processing + engine plugin environment. + + + This endpoint is synchronous and blocks until the requirements are installed. + + + ### Related + + + - [Processing engine and Python plugins](/influxdb3/core/plugins/) + + - [Python requirements file format](https://pip.pypa.io/en/stable/reference/requirements-file-format/) + parameters: + - $ref: "#/components/parameters/ContentType" + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + requirements_location: + type: string + description: | + The path to the requirements file containing Python packages to install. + Can be a relative path (relative to the plugin directory) or an absolute path. + example: requirements.txt + required: + - requirements_location + example: + requirements_location: requirements.txt + responses: + "200": + description: Success. The requirements have been installed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + tags: + - Processing engine + /api/v3/configure/processing_engine_trigger: + post: + operationId: PostConfigureProcessingEngineTrigger + summary: Create processing engine trigger + description: Creates a processing engine trigger with the specified plugin file and trigger specification. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessingEngineTriggerRequest" examples: schedule_cron: summary: Schedule trigger using cron - description: | + description: > In `"cron:CRON_EXPRESSION"`, `CRON_EXPRESSION` uses extended 6-field cron format. - The cron expression `0 0 6 * * 1-5` means the trigger will run at 6:00 AM every weekday (Monday to Friday). + + The cron expression `0 0 6 * * 1-5` means the trigger will run at 6:00 AM every weekday (Monday to + Friday). value: db: DATABASE_NAME plugin_filename: schedule.py @@ -1597,13 +887,13 @@ paths: run_async: false error_behavior: Log responses: - '200': + "200": description: Success. Processing engine trigger created. - '400': + "400": description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': + "401": + $ref: "#/components/responses/Unauthorized" + "404": description: Trigger not found. tags: - Processing engine @@ -1612,7 +902,7 @@ paths: summary: Delete processing engine trigger description: Deletes a processing engine trigger. parameters: - - $ref: '#/components/parameters/db' + - $ref: "#/components/parameters/db" - name: trigger_name in: query required: true @@ -1628,13 +918,13 @@ paths: Force deletion of the trigger even if it has active executions. By default, deletion fails if the trigger is currently executing. responses: - '200': + "200": description: Success. The processing engine trigger has been deleted. - '400': + "400": description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': + "401": + $ref: "#/components/responses/Unauthorized" + "404": description: Trigger not found. tags: - Processing engine @@ -1644,21 +934,26 @@ paths: summary: Disable processing engine trigger description: Disables a processing engine trigger. parameters: - - $ref: '#/components/parameters/ContentType' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ProcessingEngineTriggerRequest' + - name: db + in: query + required: true + schema: + type: string + description: The database name. + - name: trigger_name + in: query + required: true + schema: + type: string + description: The name of the trigger. responses: - '200': + "200": description: Success. The processing engine trigger has been disabled. - '400': + "400": description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': + "401": + $ref: "#/components/responses/Unauthorized" + "404": description: Trigger not found. tags: - Processing engine @@ -1668,89 +963,192 @@ paths: summary: Enable processing engine trigger description: Enables a processing engine trigger. parameters: - - $ref: '#/components/parameters/ContentType' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ProcessingEngineTriggerRequest' + - name: db + in: query + required: true + schema: + type: string + description: The database name. + - name: trigger_name + in: query + required: true + schema: + type: string + description: The name of the trigger. responses: - '200': + "200": description: Success. The processing engine trigger is enabled. - '400': + "400": description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': + "401": + $ref: "#/components/responses/Unauthorized" + "404": description: Trigger not found. tags: - Processing engine - /api/v3/configure/plugin_environment/install_packages: - post: - operationId: PostInstallPluginPackages - summary: Install plugin packages - description: | - Installs the specified Python packages into the processing engine plugin environment. - - This endpoint is synchronous and blocks until the packages are installed. - - ### Related guides - - - [Processing engine and Python plugins](/influxdb3/enterprise/plugins/) + /api/v3/configure/table: + delete: + operationId: DeleteConfigureTable parameters: - - $ref: '#/components/parameters/ContentType' - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - packages: - type: array - items: - type: string - description: | - A list of Python package names to install. - Can include version specifiers (e.g., "scipy==1.9.0"). - example: - - influxdb3-python - - scipy - - pandas==1.5.0 - - requests - required: - - packages - example: - packages: - - influxdb3-python - - scipy - - pandas==1.5.0 - - requests + - $ref: "#/components/parameters/db" + - name: table + in: query + required: true + schema: + type: string + - name: data_only + in: query + required: false + schema: + type: boolean + default: false + description: | + Delete only data while preserving the table schema and all associated resources + (last value caches, distinct value caches). + When `false` (default), the entire table is deleted. + - name: hard_delete_at + in: query + required: false + schema: + type: string + format: date-time + description: |- + Schedule the table for hard deletion at the specified time. + If not provided, the table will be soft deleted. + Use ISO 8601 format (for example, "2025-12-31T23:59:59Z"). + + + Also accepts special string values: + - `now` — hard delete immediately + - `never` — soft delete only (default behavior) + - `default` — use the system default hard deletion time responses: - '200': - description: Success. The packages are installed. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - tags: - - Processing engine - /api/v3/configure/plugin_environment/install_requirements: - post: - operationId: PostInstallPluginRequirements - summary: Install plugin requirements + "200": + description: Success (no content). The table has been deleted. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Table not found. + summary: Delete a table description: | - Installs requirements from a requirements file (also known as a "pip requirements file") into the processing engine plugin environment. + Soft deletes a table. + The table is scheduled for deletion and unavailable for querying. + Use the `hard_delete_at` parameter to schedule a hard deletion. + Use the `data_only` parameter to delete data while preserving the table schema and resources. - This endpoint is synchronous and blocks until the requirements are installed. + #### Deleting a table cannot be undone - ### Related - - - [Processing engine and Python plugins](/influxdb3/enterprise/plugins/) - - [Python requirements file format](https://pip.pypa.io/en/stable/reference/requirements-file-format/) + Deleting a table is a destructive action. + Once a table is deleted, data stored in that table cannot be recovered. + tags: + - Table + post: + operationId: PostConfigureTable + responses: + "200": + description: Success. The table has been created. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + summary: Create a table + description: Creates a new table within a database. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateTableRequest" + tags: + - Table + /api/v3/configure/token: + delete: + operationId: DeleteToken parameters: - - $ref: '#/components/parameters/ContentType' + - name: token_name + in: query + required: true + schema: + type: string + description: The name of the token to delete. + responses: + "200": + description: Success. The token has been deleted. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Token not found. + summary: Delete token + description: | + Deletes a token. + tags: + - Authentication + - Token + /api/v3/configure/token/admin: + post: + operationId: PostCreateAdminToken + responses: + "201": + description: | + Success. The admin token has been created. + The response body contains the token string and metadata. + content: + application/json: + schema: + $ref: "#/components/schemas/AdminTokenObject" + "401": + $ref: "#/components/responses/Unauthorized" + summary: Create admin token + description: | + Creates an admin token. + An admin token is a special type of token that has full access to all resources in the system. + tags: + - Authentication + - Token + /api/v3/configure/token/admin/regenerate: + post: + operationId: PostRegenerateAdminToken + summary: Regenerate admin token + description: | + Regenerates an admin token and revokes the previous token with the same name. + parameters: [] + responses: + "201": + description: Success. The admin token has been regenerated. + content: + application/json: + schema: + $ref: "#/components/schemas/AdminTokenObject" + "401": + $ref: "#/components/responses/Unauthorized" + tags: + - Authentication + - Token + /api/v3/configure/token/named_admin: + post: + operationId: PostCreateNamedAdminToken + responses: + "201": + description: | + Success. The named admin token has been created. + The response body contains the token string and metadata. + content: + application/json: + schema: + $ref: "#/components/schemas/AdminTokenObject" + "401": + $ref: "#/components/responses/Unauthorized" + "409": + description: A token with this name already exists. + summary: Create named admin token + description: | + Creates a named admin token. + A named admin token is a special type of admin token with a custom name for identification and management. + tags: + - Authentication + - Token requestBody: required: true content: @@ -1758,70 +1156,93 @@ paths: schema: type: object properties: - requirements_location: + token_name: type: string - description: | - The path to the requirements file containing Python packages to install. - Can be a relative path (relative to the plugin directory) or an absolute path. - example: requirements.txt + description: The name for the admin token. + expiry_secs: + type: integer + description: Optional expiration time in seconds. If not provided, the token does not expire. + nullable: true required: - - requirements_location - example: - requirements_location: requirements.txt - responses: - '200': - description: Success. The requirements have been installed. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - tags: - - Processing engine - /api/v3/plugin_test/wal: - post: - operationId: PostTestWALPlugin - summary: Test WAL plugin - description: Executes a test of a write-ahead logging (WAL) plugin. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/WALPluginTestRequest' - responses: - '200': - description: Success. The plugin test has been executed. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Plugin not enabled. - tags: - - Processing engine - /api/v3/plugin_test/schedule: - post: - operationId: PostTestSchedulingPlugin - summary: Test scheduling plugin - description: Executes a test of a scheduling plugin. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/SchedulePluginTestRequest' - responses: - '200': - description: Success. The plugin test has been executed. - '400': - description: Bad request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Plugin not enabled. - tags: - - Processing engine + - token_name /api/v3/engine/{request_path}: + get: + operationId: GetProcessingEnginePluginRequest + responses: + "200": + description: Success. The plugin request has been executed. + "400": + description: Malformed request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not found. + "500": + description: Processing failure. + summary: On Request processing engine plugin request + description: > + Executes the On Request processing engine plugin specified in the trigger's `plugin_filename`. + + The request can include request headers, query string parameters, and a request body, which InfluxDB passes to + the plugin. + + + An On Request plugin implements the following signature: + + + ```python + + def process_request(influxdb3_local, query_parameters, request_headers, request_body, args=None) + + ``` + + + The response depends on the plugin implementation. + tags: + - Processing engine + post: + operationId: PostProcessingEnginePluginRequest + responses: + "200": + description: Success. The plugin request has been executed. + "400": + description: Malformed request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not found. + "500": + description: Processing failure. + summary: On Request processing engine plugin request + description: > + Executes the On Request processing engine plugin specified in the trigger's `plugin_filename`. + + The request can include request headers, query string parameters, and a request body, which InfluxDB passes to + the plugin. + + + An On Request plugin implements the following signature: + + + ```python + + def process_request(influxdb3_local, query_parameters, request_headers, request_body, args=None) + + ``` + + + The response depends on the plugin implementation. + parameters: + - $ref: "#/components/parameters/ContentType" + requestBody: + required: false + content: + application/json: + schema: + type: object + additionalProperties: true + tags: + - Processing engine parameters: - name: request_path description: | @@ -1842,229 +1263,1064 @@ paths: required: true schema: type: string - get: - operationId: GetProcessingEnginePluginRequest - summary: On Request processing engine plugin request - description: | - Executes the On Request processing engine plugin specified in the trigger's `plugin_filename`. - The request can include request headers, query string parameters, and a request body, which InfluxDB passes to the plugin. - - An On Request plugin implements the following signature: - - ```python - def process_request(influxdb3_local, query_parameters, request_headers, request_body, args=None) - ``` - - The response depends on the plugin implementation. - responses: - '200': - description: Success. The plugin request has been executed. - '400': - description: Malformed request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Plugin not found. - '500': - description: Processing failure. - tags: - - Processing engine + /api/v3/plugin_test/schedule: post: - operationId: PostProcessingEnginePluginRequest - summary: On Request processing engine plugin request - description: | - Executes the On Request processing engine plugin specified in the trigger's `plugin_filename`. - The request can include request headers, query string parameters, and a request body, which InfluxDB passes to the plugin. - - An On Request plugin implements the following signature: - - ```python - def process_request(influxdb3_local, query_parameters, request_headers, request_body, args=None) - ``` - - The response depends on the plugin implementation. - parameters: - - $ref: '#/components/parameters/ContentType' - requestBody: - required: false - content: - application/json: - schema: - type: object - additionalProperties: true + operationId: PostTestSchedulingPlugin responses: - '200': - description: Success. The plugin request has been executed. - '400': - description: Malformed request. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Plugin not found. - '500': - description: Processing failure. - tags: - - Processing engine - /api/v3/configure/enterprise/token: - post: - operationId: PostCreateResourceToken - summary: Create a resource token - description: | - Creates a resource (fine-grained permissions) token. - A resource token is a token that has access to specific resources in the system. - - This endpoint is only available in InfluxDB 3 Enterprise. - responses: - '201': - description: | - Success. The resource token has been created. - The response body contains the token string and metadata. - content: - application/json: - schema: - $ref: '#/components/schemas/ResourceTokenObject' - '401': - $ref: '#/components/responses/Unauthorized' - tags: - - Authentication - - Token - /api/v3/configure/token/admin: - post: - operationId: PostCreateAdminToken - summary: Create admin token - description: | - Creates an admin token. - An admin token is a special type of token that has full access to all resources in the system. - responses: - '201': - description: | - Success. The admin token has been created. - The response body contains the token string and metadata. - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTokenObject' - '401': - $ref: '#/components/responses/Unauthorized' - tags: - - Authentication - - Token - /api/v3/configure/token/admin/regenerate: - post: - operationId: PostRegenerateAdminToken - summary: Regenerate admin token - description: | - Regenerates an admin token and revokes the previous token with the same name. - parameters: [] - responses: - '201': - description: Success. The admin token has been regenerated. - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTokenObject' - '401': - $ref: '#/components/responses/Unauthorized' - tags: - - Authentication - - Token - /api/v3/configure/token: - delete: - operationId: DeleteToken - summary: Delete token - description: | - Deletes a token. - parameters: - - name: id - in: query - required: true - schema: - type: string - description: The ID of the token to delete. - responses: - '204': - description: Success. The token has been deleted. - '401': - $ref: '#/components/responses/Unauthorized' - '404': - description: Token not found. - tags: - - Authentication - - Token - /api/v3/configure/token/named_admin: - post: - operationId: PostCreateNamedAdminToken - summary: Create named admin token - description: | - Creates a named admin token. - A named admin token is a special type of admin token with a custom name for identification and management. - parameters: - - name: name - in: query - required: true - schema: - type: string - description: The name for the admin token. - responses: - '201': - description: | - Success. The named admin token has been created. - The response body contains the token string and metadata. - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTokenObject' - '401': - $ref: '#/components/responses/Unauthorized' - '409': - description: A token with this name already exists. - tags: - - Authentication - - Token - /api/v3/plugins/files: - put: - operationId: PutPluginFile - summary: Update plugin file - description: | - Updates a plugin file in the plugin directory. - x-security-note: Requires an admin token + "200": + description: Success. The plugin test has been executed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not enabled. + summary: Test scheduling plugin + description: Executes a test of a scheduling plugin. requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/PluginFileRequest' + $ref: "#/components/schemas/SchedulePluginTestRequest" + tags: + - Processing engine + /api/v3/plugin_test/wal: + post: + operationId: PostTestWALPlugin responses: - '204': - description: Success. The plugin file has been updated. - '401': - $ref: '#/components/responses/Unauthorized' - '403': - description: Forbidden. Admin token required. + "200": + description: Success. The plugin test has been executed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not enabled. + summary: Test WAL plugin + description: Executes a test of a write-ahead logging (WAL) plugin. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/WALPluginTestRequest" tags: - Processing engine /api/v3/plugins/directory: put: operationId: PutPluginDirectory - summary: Update plugin directory - description: | - Updates the plugin directory configuration. - x-security-note: Requires an admin token requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/PluginDirectoryRequest' + $ref: "#/components/schemas/PluginDirectoryRequest" responses: - '204': + "200": description: Success. The plugin directory has been updated. - '401': - $ref: '#/components/responses/Unauthorized' - '403': + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Forbidden. Admin token required. + "500": + description: Plugin not found. The `plugin_name` does not match any registered trigger. + summary: Update a multi-file plugin directory + description: | + Replaces all files in a multi-file plugin directory. The + `plugin_name` must match a registered trigger name. Each entry in + the `files` array specifies a `relative_path` and `content`—the + server writes them into the trigger's plugin directory. + + Use this endpoint to update multi-file plugins (directories with + `__init__.py` and supporting modules). For single-file plugins, + use `PUT /api/v3/plugins/files` instead. + tags: + - Processing engine + x-security-note: Requires an admin token + /api/v3/plugins/files: + post: + operationId: create_plugin_file + summary: Create a plugin file + description: | + Creates a single plugin file in the plugin directory. Writes the + `content` to a file named after `plugin_name`. Does not require an + existing trigger—use this to upload plugin files before creating + triggers that reference them. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PluginFileRequest" + responses: + "200": + description: Success. The plugin file has been created. + "401": + $ref: "#/components/responses/Unauthorized" + "403": description: Forbidden. Admin token required. tags: - Processing engine + x-security-note: Requires an admin token + put: + operationId: PutPluginFile + summary: Update a plugin file + description: | + Updates a single plugin file for an existing trigger. The + `plugin_name` must match a registered trigger name—the server + resolves the trigger's `plugin_filename` and overwrites that file + with the provided `content`. + + To upload a new plugin file before creating a trigger, use + `POST /api/v3/plugins/files` instead. To update a multi-file + plugin directory, use `PUT /api/v3/plugins/directory`. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PluginFileRequest" + responses: + "200": + description: Success. The plugin file has been updated. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Forbidden. Admin token required. + "500": + description: Plugin not found. The `plugin_name` does not match any registered trigger. + tags: + - Processing engine + x-security-note: Requires an admin token + /api/v3/query_influxql: + get: + operationId: GetExecuteInfluxQLQuery + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query + description: Executes an InfluxQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/dbQueryParam" + - name: q + in: query + required: true + schema: + type: string + - name: format + in: query + required: false + schema: + type: string + - $ref: "#/components/parameters/AcceptQueryHeader" + - name: params + in: query + required: false + schema: + type: string + description: JSON-encoded query parameters. Use this to pass bind parameters to parameterized queries. + description: JSON-encoded query parameters for parameterized queries. + tags: + - Query data + post: + operationId: PostExecuteQueryInfluxQL + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query + description: Executes an InfluxQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/AcceptQueryHeader" + - $ref: "#/components/parameters/ContentType" + requestBody: + $ref: "#/components/requestBodies/queryRequestBody" + tags: + - Query data + /api/v3/query_sql: + get: + operationId: GetExecuteQuerySQL + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + example: + results: + - series: + - name: mytable + columns: + - time + - value + values: + - - "2024-02-02T12:00:00Z" + - 42 + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute SQL query + description: Executes an SQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/db" + - $ref: "#/components/parameters/querySqlParam" + - $ref: "#/components/parameters/format" + - $ref: "#/components/parameters/AcceptQueryHeader" + - $ref: "#/components/parameters/ContentType" + - name: params + in: query + required: false + schema: + type: string + description: JSON-encoded query parameters. Use this to pass bind parameters to parameterized queries. + description: JSON-encoded query parameters for parameterized queries. + tags: + - Query data + post: + operationId: PostExecuteQuerySQL + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute SQL query + description: Executes an SQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/AcceptQueryHeader" + - $ref: "#/components/parameters/ContentType" + requestBody: + $ref: "#/components/requestBodies/queryRequestBody" + tags: + - Query data + /api/v3/write_lp: + post: + operationId: PostWriteLP + parameters: + - $ref: "#/components/parameters/dbWriteParam" + - $ref: "#/components/parameters/accept_partial" + - $ref: "#/components/parameters/precisionParam" + - name: no_sync + in: query + schema: + $ref: "#/components/schemas/NoSync" + - name: Content-Type + in: header + description: | + The content type of the request payload. + schema: + $ref: "#/components/schemas/LineProtocol" + required: false + - name: Accept + in: header + description: | + The content type that the client can understand. + Writes only return a response body if they fail (partially or completely)--for example, + due to a syntax problem or type mismatch. + schema: + type: string + default: application/json + enum: + - application/json + required: false + - $ref: "#/components/parameters/ContentEncoding" + - $ref: "#/components/parameters/ContentLength" + responses: + "204": + description: Success ("No Content"). All data in the batch is written and queryable. + headers: + cluster-uuid: + $ref: "#/components/headers/ClusterUUID" + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "413": + description: Request entity too large. + "422": + description: Unprocessable entity. + summary: Write line protocol + description: > + Writes line protocol to the specified database. + + + This is the native InfluxDB 3 Core write endpoint that provides enhanced control + + over write behavior with advanced parameters for high-performance and fault-tolerant operations. + + + Use this endpoint to send data in [line protocol](/influxdb3/core/reference/syntax/line-protocol/) format to + InfluxDB. + + Use query parameters to specify options for writing data. + + + #### Features + + + - **Partial writes**: Use `accept_partial=true` to allow partial success when some lines in a batch fail + + - **Asynchronous writes**: Use `no_sync=true` to skip waiting for WAL synchronization, allowing faster response + times but sacrificing durability guarantees + + - **Flexible precision**: Automatic timestamp precision detection with `precision=auto` (default) + + + #### Auto precision detection + + + When you use `precision=auto` or omit the precision parameter, InfluxDB 3 automatically detects + + the timestamp precision based on the magnitude of the timestamp value: + + + - Timestamps < 5e9 → Second precision (multiplied by 1,000,000,000 to convert to nanoseconds) + + - Timestamps < 5e12 → Millisecond precision (multiplied by 1,000,000) + + - Timestamps < 5e15 → Microsecond precision (multiplied by 1,000) + + - Larger timestamps → Nanosecond precision (no conversion needed) + + + #### Related + + + - [Use the InfluxDB v3 write_lp API to write data](/influxdb3/core/write-data/http-api/v3-write-lp/) + requestBody: + $ref: "#/components/requestBodies/lineProtocolRequestBody" + tags: + - Write data + x-codeSamples: + - label: cURL - Basic write + lang: Shell + source: | + curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01 usage=85.2 1638360000000000000" + - label: cURL - Write with millisecond precision + lang: Shell + source: | + curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors&precision=ms" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01 usage=85.2 1638360000000" + - label: cURL - Asynchronous write with partial acceptance + lang: Shell + source: > + curl --request POST + "http://localhost:8181/api/v3/write_lp?db=sensors&accept_partial=true&no_sync=true&precision=auto" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01 usage=85.2 + memory,host=server01 used=4096" + - label: cURL - Multiple measurements with tags + lang: Shell + source: | + curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors&precision=ns" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01,region=us-west usage=85.2,load=0.75 1638360000000000000 + memory,host=server01,region=us-west used=4096,free=12288 1638360000000000000 + disk,host=server01,region=us-west,device=/dev/sda1 used=50.5,free=49.5 1638360000000000000" + /health: + get: + operationId: GetHealth + responses: + "200": + description: Service is running. Returns `OK`. + content: + text/plain: + schema: + type: string + example: OK + "401": + description: Unauthorized. Authentication is required. + "500": + description: Service is unavailable. + summary: Health check + description: | + Checks the status of the service. + + Returns `OK` if the service is running. This endpoint does not return version information. + Use the [`/ping`](#operation/GetPing) endpoint to retrieve version details. + + > **Note**: This endpoint requires authentication by default in InfluxDB 3 Core. + tags: + - Server information + /metrics: + get: + operationId: GetMetrics + responses: + "200": + description: Success + summary: Metrics + description: Retrieves Prometheus-compatible server metrics. + tags: + - Server information + /ping: + get: + operationId: GetPing + responses: + "200": + description: Success. The response body contains server information. + headers: + x-influxdb-version: + description: The InfluxDB version number (for example, `3.8.0`). + schema: + type: string + example: 3.8.0 + x-influxdb-build: + description: The InfluxDB build type (`Core` or `Enterprise`). + schema: + type: string + example: Core + content: + application/json: + schema: + type: object + properties: + version: + type: string + description: The InfluxDB version number. + example: 3.8.0 + revision: + type: string + description: The git revision hash for the build. + example: 83b589b883 + process_id: + type: string + description: A unique identifier for the server process. + example: b756d9e0-cecd-4f72-b6d0-19e2d4f8cbb7 + "401": + description: Unauthorized. Authentication is required. + "404": + description: | + Not Found. Returned for HEAD requests. + Use a GET request to retrieve version information. + x-client-method: ping + summary: Ping the server + description: | + Returns version information for the server. + + **Important**: Use a GET request. HEAD requests return `404 Not Found`. + + The response includes version information in both headers and the JSON body: + + - **Headers**: `x-influxdb-version` and `x-influxdb-build` + - **Body**: JSON object with `version`, `revision`, and `process_id` + + > **Note**: This endpoint requires authentication by default in InfluxDB 3 Core. + tags: + - Server information + post: + operationId: ping + responses: + "200": + description: Success. The response body contains server information. + headers: + x-influxdb-version: + description: The InfluxDB version number (for example, `3.8.0`). + schema: + type: string + example: 3.8.0 + x-influxdb-build: + description: The InfluxDB build type (`Core` or `Enterprise`). + schema: + type: string + example: Core + content: + application/json: + schema: + type: object + properties: + version: + type: string + description: The InfluxDB version number. + example: 3.8.0 + revision: + type: string + description: The git revision hash for the build. + example: 83b589b883 + process_id: + type: string + description: A unique identifier for the server process. + example: b756d9e0-cecd-4f72-b6d0-19e2d4f8cbb7 + "401": + description: Unauthorized. Authentication is required. + "404": + description: | + Not Found. Returned for HEAD requests. + Use a GET request to retrieve version information. + summary: Ping the server + description: Returns version information for the server. Accepts POST in addition to GET. + tags: + - Server information + /query: + get: + operationId: GetV1ExecuteQuery + responses: + "200": + description: | + Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + application/csv: + schema: + type: string + headers: + Content-Type: + description: > + The content type of the response. + + Default is `application/json`. + + + If the `Accept` request header is `application/csv` or `text/csv`, the `Content-type` response header is + `application/csv` + + and the response is formatted as CSV. + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query (v1-compatible) + description: > + Executes an InfluxQL query to retrieve data from the specified database. + + + This endpoint is compatible with InfluxDB 1.x client libraries and third-party integrations such as Grafana. + + Use query parameters to specify the database and the InfluxQL query. + + + #### Related + + + - [Use the InfluxDB v1 HTTP query API and InfluxQL to query + data](/influxdb3/core/query-data/execute-queries/influxdb-v1-api/) + parameters: + - name: Accept + in: header + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + - text/csv + required: false + description: > + The content type that the client can understand. + + + If `text/csv` is specified, the `Content-type` response header is `application/csv` and the response is + formatted as CSV. + + + Returns an error if the format is invalid or non-UTF8. + - in: query + name: chunked + description: | + If true, the response is divided into chunks of size `chunk_size`. + schema: + type: boolean + default: false + - in: query + name: chunk_size + description: | + The number of records that will go into a chunk. + This parameter is only used if `chunked=true`. + schema: + type: integer + default: 10000 + - in: query + name: db + description: The database to query. If not provided, the InfluxQL query string must specify the database. + schema: + type: string + format: InfluxQL + - in: query + name: pretty + description: | + If true, the JSON response is formatted in a human-readable format. + schema: + type: boolean + default: false + - in: query + name: q + description: The InfluxQL query string. + required: true + schema: + type: string + - name: epoch + description: > + Formats timestamps as [unix (epoch) timestamps](/influxdb3/core/reference/glossary/#unix-timestamp) with the + specified precision + + instead of [RFC3339 timestamps](/influxdb3/core/reference/glossary/#rfc3339-timestamp) with nanosecond + precision. + in: query + schema: + $ref: "#/components/schemas/EpochCompatibility" + - $ref: "#/components/parameters/v1UsernameParam" + - $ref: "#/components/parameters/v1PasswordParam" + - name: rp + in: query + required: false + schema: + type: string + description: | + Retention policy name. Honored but discouraged. InfluxDB 3 doesn't use retention policies. + - name: Authorization + in: header + required: false + schema: + type: string + description: | + Authorization header for token-based authentication. + Supported schemes: + - `Bearer AUTH_TOKEN` - OAuth bearer token scheme + - `Token AUTH_TOKEN` - InfluxDB v2 token scheme + - `Basic ` - Basic authentication (username is ignored) + tags: + - Query data + - Compatibility endpoints + post: + operationId: PostExecuteV1Query + responses: + "200": + description: | + Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + application/csv: + schema: + type: string + headers: + Content-Type: + description: > + The content type of the response. + + Default is `application/json`. + + + If the `Accept` request header is `application/csv` or `text/csv`, the `Content-type` response header is + `application/csv` + + and the response is formatted as CSV. + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query (v1-compatible) + description: > + Executes an InfluxQL query to retrieve data from the specified database. + + + #### Related + + + - [Use the InfluxDB v1 HTTP query API and InfluxQL to query + data](/influxdb3/core/query-data/execute-queries/influxdb-v1-api/) + parameters: + - name: Accept + in: header + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + - text/csv + required: false + description: > + The content type that the client can understand. + + + If `text/csv` is specified, the `Content-type` response header is `application/csv` and the response is + formatted as CSV. + + + Returns an error if the format is invalid or non-UTF8. + requestBody: + content: + application/json: + schema: + type: object + properties: + db: + type: string + description: The database to query. If not provided, the InfluxQL query string must specify the database. + q: + description: The InfluxQL query string. + type: string + chunked: + description: | + If true, the response is divided into chunks of size `chunk_size`. + type: boolean + chunk_size: + description: | + The number of records that will go into a chunk. + This parameter is only used if `chunked=true`. + type: integer + default: 10000 + epoch: + description: > + A unix timestamp precision. + + + - `h` for hours + + - `m` for minutes + + - `s` for seconds + + - `ms` for milliseconds + + - `u` or `µ` for microseconds + + - `ns` for nanoseconds + + + Formats timestamps as [unix (epoch) timestamps](/influxdb3/core/reference/glossary/#unix-timestamp) + with the specified precision + + instead of [RFC3339 timestamps](/influxdb3/core/reference/glossary/#rfc3339-timestamp) with + nanosecond precision. + enum: + - ns + - u + - µ + - ms + - s + - m + - h + type: string + pretty: + description: | + If true, the JSON response is formatted in a human-readable format. + type: boolean + required: + - q + application/x-www-form-urlencoded: + schema: + type: object + properties: + db: + type: string + description: The database to query. If not provided, the InfluxQL query string must specify the database. + q: + description: The InfluxQL query string. + type: string + chunked: + description: | + If true, the response is divided into chunks of size `chunk_size`. + type: boolean + chunk_size: + description: | + The number of records that will go into a chunk. + This parameter is only used if `chunked=true`. + type: integer + default: 10000 + epoch: + description: > + A unix timestamp precision. + + + - `h` for hours + + - `m` for minutes + + - `s` for seconds + + - `ms` for milliseconds + + - `u` or `µ` for microseconds + + - `ns` for nanoseconds + + + Formats timestamps as [unix (epoch) timestamps](/influxdb3/core/reference/glossary/#unix-timestamp) + with the specified precision + + instead of [RFC3339 timestamps](/influxdb3/core/reference/glossary/#rfc3339-timestamp) with + nanosecond precision. + enum: + - ns + - u + - µ + - ms + - s + - m + - h + type: string + pretty: + description: | + If true, the JSON response is formatted in a human-readable format. + type: boolean + required: + - q + application/vnd.influxql: + schema: + type: string + description: InfluxQL query string sent as the request body. + tags: + - Query data + - Compatibility endpoints + /write: + post: + operationId: PostV1Write + responses: + "204": + description: Success ("No Content"). All data in the batch is written and queryable. + headers: + cluster-uuid: + $ref: "#/components/headers/ClusterUUID" + "400": + description: | + Bad request. Some (a _partial write_) or all of the data from the batch was rejected and not written. + If a partial write occurred, then some points from the batch are written and queryable. + + The response body: + - indicates if a partial write occurred or all data was rejected. + - contains details about the [rejected points](/influxdb3/core/write-data/troubleshoot/#troubleshoot-rejected-points), up to 100 points. + content: + application/json: + examples: + rejectedAllPoints: + summary: Rejected all points in the batch + value: | + { + "error": "write of line protocol failed", + "data": [ + { + "original_line": "dquote> home,room=Kitchen temp=hi", + "line_number": 2, + "error_message": "No fields were provided" + } + ] + } + partialWriteErrorWithRejectedPoints: + summary: Partial write rejected some points in the batch + value: | + { + "error": "partial write of line protocol occurred", + "data": [ + { + "original_line": "dquote> home,room=Kitchen temp=hi", + "line_number": 2, + "error_message": "No fields were provided" + } + ] + } + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "413": + description: Request entity too large. + summary: Write line protocol (v1-compatible) + description: > + Writes line protocol to the specified database. + + + This endpoint provides backward compatibility for InfluxDB 1.x write workloads using tools such as InfluxDB 1.x + client libraries, the Telegraf `outputs.influxdb` output plugin, or third-party tools. + + + Use this endpoint to send data in [line + protocol](https://docs.influxdata.com/influxdb3/core/reference/syntax/line-protocol/) format to InfluxDB. + + Use query parameters to specify options for writing data. + + + #### Related + + + - [Use compatibility APIs to write data](/influxdb3/core/write-data/http-api/compatibility-apis/) + parameters: + - $ref: "#/components/parameters/dbWriteParam" + - $ref: "#/components/parameters/compatibilityPrecisionParam" + - $ref: "#/components/parameters/v1UsernameParam" + - $ref: "#/components/parameters/v1PasswordParam" + - name: rp + in: query + required: false + schema: + type: string + description: | + Retention policy name. Honored but discouraged. InfluxDB 3 doesn't use retention policies. + - name: consistency + in: query + required: false + schema: + type: string + description: | + Write consistency level. Ignored by InfluxDB 3. Provided for compatibility with InfluxDB 1.x clients. + - name: Authorization + in: header + required: false + schema: + type: string + description: | + Authorization header for token-based authentication. + Supported schemes: + - `Bearer AUTH_TOKEN` - OAuth bearer token scheme + - `Token AUTH_TOKEN` - InfluxDB v2 token scheme + - `Basic ` - Basic authentication (username is ignored) + - name: Content-Type + in: header + description: | + The content type of the request payload. + schema: + $ref: "#/components/schemas/LineProtocol" + required: false + - name: Accept + in: header + description: | + The content type that the client can understand. + Writes only return a response body if they fail (partially or completely)--for example, + due to a syntax problem or type mismatch. + schema: + type: string + default: application/json + enum: + - application/json + required: false + - $ref: "#/components/parameters/ContentEncoding" + - $ref: "#/components/parameters/ContentLength" + requestBody: + $ref: "#/components/requestBodies/lineProtocolRequestBody" + tags: + - Compatibility endpoints + - Write data components: parameters: AcceptQueryHeader: @@ -2088,7 +2344,7 @@ components: The compression applied to the line protocol in the request payload. To send a gzip payload, pass `Content-Encoding: gzip` header. schema: - $ref: '#/components/schemas/ContentEncoding' + $ref: "#/components/schemas/ContentEncoding" required: false ContentLength: name: Content-Length @@ -2096,7 +2352,7 @@ components: description: | The size of the entity-body, in bytes, sent to InfluxDB. schema: - $ref: '#/components/schemas/ContentLength' + $ref: "#/components/schemas/ContentLength" ContentType: name: Content-Type description: | @@ -2140,20 +2396,20 @@ components: in: query required: false schema: - $ref: '#/components/schemas/AcceptPartial' + $ref: "#/components/schemas/AcceptPartial" compatibilityPrecisionParam: name: precision in: query - required: true + required: false schema: - $ref: '#/components/schemas/PrecisionWriteCompatibility' + $ref: "#/components/schemas/PrecisionWriteCompatibility" description: The precision for unix timestamps in the line protocol batch. precisionParam: name: precision in: query - required: true + required: false schema: - $ref: '#/components/schemas/PrecisionWrite' + $ref: "#/components/schemas/PrecisionWrite" description: The precision for unix timestamps in the line protocol batch. querySqlParam: name: q @@ -2169,22 +2425,24 @@ components: in: query required: false schema: - $ref: '#/components/schemas/Format' + $ref: "#/components/schemas/Format" formatRequired: name: format in: query required: true schema: - $ref: '#/components/schemas/Format' + $ref: "#/components/schemas/Format" v1UsernameParam: name: u in: query required: false schema: type: string - description: | + description: > Username for v1 compatibility authentication. - When using Basic authentication or query string authentication, InfluxDB 3 ignores this parameter but allows any arbitrary string for compatibility with InfluxDB 1.x clients. + + When using Basic authentication or query string authentication, InfluxDB 3 ignores this parameter but allows any + arbitrary string for compatibility with InfluxDB 1.x clients. v1PasswordParam: name: p in: query @@ -2217,7 +2475,7 @@ components: content: application/json: schema: - $ref: '#/components/schemas/QueryRequestObject' + $ref: "#/components/schemas/QueryRequestObject" schemas: AdminTokenObject: type: object @@ -2240,61 +2498,31 @@ components: name: _admin token: apiv3_00xx0Xx0xx00XX0x0 hash: 00xx0Xx0xx00XX0x0 - created_at: '2025-04-18T14:02:45.331Z' + created_at: "2025-04-18T14:02:45.331Z" expiry: null - ResourceTokenObject: - type: object - properties: - token_name: - type: string - permissions: - type: array - items: - type: object - properties: - resource_type: - type: string - enum: - - system - - db - resource_identifier: - type: array - items: - type: string - actions: - type: array - items: - type: string - enum: - - read - - write - expiry_secs: - type: integer - description: The expiration time in seconds. - example: - token_name: All system information - permissions: - - resource_type: system - resource_identifier: - - '*' - actions: - - read - expiry_secs: 300000 ContentEncoding: type: string enum: - gzip - identity - description: | + description: > Content coding. + Use `gzip` for compressed data or `identity` for unmodified, uncompressed data. + #### Multi-member gzip support - InfluxDB 3 supports multi-member gzip payloads (concatenated gzip files per [RFC 1952](https://www.rfc-editor.org/rfc/rfc1952)). + + InfluxDB 3 supports multi-member gzip payloads (concatenated gzip files per [RFC + 1952](https://www.rfc-editor.org/rfc/rfc1952)). + This allows you to: + - Concatenate multiple gzip files and send them in a single request + - Maintain compatibility with InfluxDB v1 and v2 write endpoints + - Simplify batch operations using standard compression tools default: identity LineProtocol: @@ -2308,8 +2536,6 @@ components: ContentLength: type: integer description: The length in decimal number of octets. - Database: - type: string AcceptPartial: type: boolean default: true @@ -2320,9 +2546,12 @@ components: - json - csv - parquet + - json_lines - jsonl - description: | + - pretty + description: |- The format of data in the response body. + `json_lines` is the canonical name; `jsonl` is accepted as an alias. NoSync: type: boolean default: false @@ -2331,18 +2560,21 @@ components: #### Related - - [Use the HTTP API and client libraries to write data](/influxdb3/enterprise/write-data/api-client-libraries/) - - [Data durability](/influxdb3/enterprise/reference/internals/durability/) + - [Use the HTTP API and client libraries to write data](/influxdb3/core/write-data/api-client-libraries/) + - [Data durability](/influxdb3/core/reference/internals/durability/) PrecisionWriteCompatibility: enum: - ms - s - us + - u - ns + - "n" type: string - description: | + description: |- The precision for unix timestamps in the line protocol batch. - Use `ms` for milliseconds, `s` for seconds, `us` for microseconds, or `ns` for nanoseconds. + Use `ms` for milliseconds, `s` for seconds, `us` or `u` for microseconds, or `ns` or `n` for nanoseconds. + Optional — defaults to nanosecond precision if omitted. PrecisionWrite: enum: - auto @@ -2378,6 +2610,7 @@ components: - json - csv - parquet + - json_lines - jsonl - pretty params: @@ -2458,8 +2691,6 @@ components: type: string table: type: string - node_spec: - $ref: '#/components/schemas/ApiNodeSpec' name: type: string description: Optional cache name. @@ -2492,8 +2723,6 @@ components: type: string table: type: string - node_spec: - $ref: '#/components/schemas/ApiNodeSpec' name: type: string description: Optional cache name. @@ -2538,63 +2767,99 @@ components: The path can be absolute or relative to the `--plugins-dir` directory configured when starting InfluxDB 3. The plugin file must implement the trigger interface associated with the trigger's specification. - node_spec: - $ref: '#/components/schemas/ApiNodeSpec' trigger_name: type: string trigger_settings: description: | Configuration for trigger error handling and execution behavior. allOf: - - $ref: '#/components/schemas/TriggerSettings' + - $ref: "#/components/schemas/TriggerSettings" trigger_specification: - description: | + description: > Specifies when and how the processing engine trigger should be invoked. + ## Supported trigger specifications: + ### Cron-based scheduling + Format: `cron:CRON_EXPRESSION` + Uses extended (6-field) cron format (second minute hour day_of_month month day_of_week): + ``` + ┌───────────── second (0-59) + │ ┌───────────── minute (0-59) + │ │ ┌───────────── hour (0-23) + │ │ │ ┌───────────── day of month (1-31) + │ │ │ │ ┌───────────── month (1-12) + │ │ │ │ │ ┌───────────── day of week (0-6, Sunday=0) + │ │ │ │ │ │ + * * * * * * + ``` + Examples: + - `cron:0 0 6 * * 1-5` - Every weekday at 6:00 AM + - `cron:0 30 14 * * 5` - Every Friday at 2:30 PM + - `cron:0 0 0 1 * *` - First day of every month at midnight + ### Interval-based scheduling + Format: `every:DURATION` - Supported durations: `s` (seconds), `m` (minutes), `h` (hours), `d` (days), `w` (weeks), `M` (months), `y` (years): + + Supported durations: `s` (seconds), `m` (minutes), `h` (hours), `d` (days), `w` (weeks), `M` (months), `y` + (years): + - `every:30s` - Every 30 seconds + - `every:5m` - Every 5 minutes + - `every:1h` - Every hour + - `every:1d` - Every day + - `every:1w` - Every week + - `every:1M` - Every month + - `every:1y` - Every year + **Maximum interval**: 1 year + ### Table-based triggers + - `all_tables` - Triggers on write events to any table in the database + - `table:TABLE_NAME` - Triggers on write events to a specific table + ### On-demand triggers + Format: `request:REQUEST_PATH` + Creates an HTTP endpoint `/api/v3/engine/REQUEST_PATH` for manual invocation: + - `request:hello-world` - Creates endpoint `/api/v3/engine/hello-world` + - `request:data-export` - Creates endpoint `/api/v3/engine/data-export` pattern: ^(cron:[0-9 *,/-]+|every:[0-9]+[smhd]|all_tables|table:[a-zA-Z_][a-zA-Z0-9_]*|request:[a-zA-Z0-9_-]+)$ example: cron:0 0 6 * * 1-5 @@ -2640,22 +2905,6 @@ components: required: - run_async - error_behavior - ApiNodeSpec: - type: object - description: | - Optional specification for targeting specific nodes in a multi-node InfluxDB 3 Enterprise cluster. - Use this to control which node(s) should handle the cache or trigger. - properties: - node_id: - type: string - description: | - The ID of a specific node in the cluster. - If specified, the cache or trigger will only be created on this node. - node_group: - type: string - description: | - The name of a node group in the cluster. - If specified, the cache or trigger will be created on all nodes in this group. WALPluginTestRequest: type: object description: | @@ -2745,7 +2994,7 @@ components: files: type: array items: - $ref: '#/components/schemas/PluginFileEntry' + $ref: "#/components/schemas/PluginFileEntry" description: | List of plugin files to include in the directory. required: @@ -2756,16 +3005,15 @@ components: description: | Represents a single file in a plugin directory. properties: - filename: - type: string - description: | - The name of the file within the plugin directory. content: type: string description: | The content of the file. + relative_path: + type: string + description: The relative path of the file within the plugin directory. required: - - filename + - relative_path - content ShowDatabasesResponse: type: object @@ -2789,7 +3037,7 @@ components: - time - value values: - - - '2024-02-02T12:00:00Z' + - - "2024-02-02T12:00:00Z" - 42 ErrorMessage: type: object @@ -2799,38 +3047,6 @@ components: data: type: object nullable: true - LineProtocolError: - properties: - code: - description: Code is the machine-readable error code. - enum: - - internal error - - not found - - conflict - - invalid - - empty value - - unavailable - readOnly: true - type: string - err: - description: Stack of errors that occurred during processing of the request. Useful for debugging. - readOnly: true - type: string - line: - description: First line in the request body that contains malformed data. - format: int32 - readOnly: true - type: integer - message: - description: Human-readable message. - readOnly: true - type: string - op: - description: Describes the logical code operation when the error occurred. Useful for debugging. - readOnly: true - type: string - required: - - code EpochCompatibility: description: | A unix timestamp precision. @@ -2859,62 +3075,13 @@ components: Use duration format (for example, "1d", "1h", "30m", "7d"). example: 7d description: Request schema for updating database configuration. - UpdateTableRequest: - type: object - properties: - db: - type: string - description: The name of the database containing the table. - table: - type: string - description: The name of the table to update. - retention_period: - type: string - description: | - The retention period for the table. Specifies how long data in this table should be retained. - Use duration format (for example, "1d", "1h", "30m", "7d"). - example: 30d - required: - - db - - table - description: Request schema for updating table configuration. - LicenseResponse: - type: object - properties: - license_type: - type: string - description: The type of license (for example, "enterprise", "trial"). - example: enterprise - expires_at: - type: string - format: date-time - description: The expiration date of the license in ISO 8601 format. - example: '2025-12-31T23:59:59Z' - features: - type: array - items: - type: string - description: List of features enabled by the license. - example: - - clustering - - processing_engine - - advanced_auth - status: - type: string - enum: - - active - - expired - - invalid - description: The current status of the license. - example: active - description: Response schema for license information. responses: Unauthorized: description: Unauthorized access. content: application/json: schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: "#/components/schemas/ErrorMessage" BadRequest: description: | Request failed. Possible reasons: @@ -2925,19 +3092,19 @@ components: content: application/json: schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: "#/components/schemas/ErrorMessage" Forbidden: description: Access denied. content: application/json: schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: "#/components/schemas/ErrorMessage" NotFound: description: Resource not found. content: application/json: schema: - $ref: '#/components/schemas/ErrorMessage' + $ref: "#/components/schemas/ErrorMessage" headers: ClusterUUID: description: | @@ -2954,94 +3121,126 @@ components: BasicAuthentication: type: http scheme: basic - description: | + description: >- Use the `Authorization` header with the `Basic` scheme to authenticate v1 API requests. - Works with v1 compatibility [`/write`](#operation/PostV1Write) and [`/query`](#operation/GetV1Query) endpoints in InfluxDB 3. - When authenticating requests, InfluxDB 3 checks that the `password` part of the decoded credential is an authorized token + Works with v1 compatibility [`/write`](#operation/PostV1Write) and [`/query`](#operation/GetV1Query) endpoints + in InfluxDB 3. + + + When authenticating requests, InfluxDB 3 checks that the `password` part of the decoded credential is an + authorized token + and ignores the `username` part of the decoded credential. + ### Syntax + ```http + Authorization: Basic + ``` + ### Example + ```bash + curl "http://localhost:8181/write?db=DATABASE_NAME&precision=s" \ --user "":"AUTH_TOKEN" \ --header "Content-type: text/plain; charset=utf-8" \ --data-binary 'home,room=kitchen temp=72 1641024000' ``` + Replace the following: - - **`DATABASE_NAME`**: your InfluxDB 3 Enterprise database + + - **`DATABASE_NAME`**: your InfluxDB 3 Core database + - **`AUTH_TOKEN`**: an admin token or database token authorized for the database - - #### Related guides - - - [Authenticate v1 API requests](/influxdb3/enterprise/guides/api-compatibility/v1/) - - [Manage tokens](/influxdb3/enterprise/admin/tokens/) QuerystringAuthentication: type: apiKey in: query name: u=&p= - description: | + description: >- Use InfluxDB 1.x API parameters to provide credentials through the query string for v1 API requests. - Querystring authentication works with v1-compatible [`/write`](#operation/PostV1Write) and [`/query`](#operation/GetV1Query) endpoints. + + Querystring authentication works with v1-compatible [`/write`](#operation/PostV1Write) and + [`/query`](#operation/GetV1Query) endpoints. + When authenticating requests, InfluxDB 3 checks that the `p` (_password_) query parameter is an authorized token + and ignores the `u` (_username_) query parameter. + ### Syntax + ```http + https://localhost:8181/query/?[u=any]&p=AUTH_TOKEN + https://localhost:8181/write/?[u=any]&p=AUTH_TOKEN + ``` + ### Examples + ```bash + curl "http://localhost:8181/write?db=DATABASE_NAME&precision=s&p=AUTH_TOKEN" \ --header "Content-type: text/plain; charset=utf-8" \ --data-binary 'home,room=kitchen temp=72 1641024000' ``` + Replace the following: - - **`DATABASE_NAME`**: your InfluxDB 3 Enterprise database + + - **`DATABASE_NAME`**: your InfluxDB 3 Core database + - **`AUTH_TOKEN`**: an admin token or database token authorized for the database + ```bash + ####################################### + # Use an InfluxDB 1.x compatible username and password + # to query the InfluxDB v1 HTTP API + ####################################### + # Use authentication query parameters: + # ?p=AUTH_TOKEN + ####################################### + curl --get "http://localhost:8181/query" \ --data-urlencode "p=AUTH_TOKEN" \ --data-urlencode "db=DATABASE_NAME" \ --data-urlencode "q=SELECT * FROM MEASUREMENT" ``` + Replace the following: + - **`DATABASE_NAME`**: the database to query + - **`AUTH_TOKEN`**: a database token with sufficient permissions to the database - - #### Related guides - - - [Authenticate v1 API requests](/influxdb3/enterprise/guides/api-compatibility/v1/) - - [Manage tokens](/influxdb3/enterprise/admin/tokens/) BearerAuthentication: type: http scheme: bearer @@ -3069,7 +3268,7 @@ components: --header "Authorization: Bearer AUTH_TOKEN" ``` TokenAuthentication: - description: | + description: |- Use InfluxDB v2 Token authentication to provide an authorization token to InfluxDB 3. The v2 Token scheme works with v1 and v2 compatibility endpoints in InfluxDB 3. @@ -3096,10 +3295,6 @@ components: --header "Authorization: Token AUTH_TOKEN" \ --data-binary 'home,room=kitchen temp=72 1463683075' ``` - - ### Related guides - - - [Manage tokens](/influxdb3/enterprise/admin/tokens/) in: header name: Authorization type: apiKey diff --git a/api-docs/influxdb3/enterprise/.config.yml b/api-docs/influxdb3/enterprise/.config.yml index 4b8210b97..d39bc413c 100644 --- a/api-docs/influxdb3/enterprise/.config.yml +++ b/api-docs/influxdb3/enterprise/.config.yml @@ -7,7 +7,7 @@ x-influxdata-product-name: InfluxDB 3 Enterprise apis: v3@3: - root: v3/ref.yml + root: v3/influxdb3-enterprise-openapi.yaml x-influxdata-docs-aliases: - /influxdb3/enterprise/api/ - /influxdb3/enterprise/api/v1/ diff --git a/api-docs/influxdb3/enterprise/v3/content/info.yml b/api-docs/influxdb3/enterprise/v3/content/info.yml index e4ec8ef60..cd2e5acdf 100644 --- a/api-docs/influxdb3/enterprise/v3/content/info.yml +++ b/api-docs/influxdb3/enterprise/v3/content/info.yml @@ -21,10 +21,7 @@ description: | - `/`: Compatibility endpoints for InfluxDB v1 workloads and clients - `/api/v2/write`: Compatibility endpoint for InfluxDB v2 workloads and clients - + [Download the OpenAPI specification](/openapi/influxdb3-enterprise-openapi.yaml) license: name: MIT url: 'https://opensource.org/licenses/MIT' diff --git a/api-docs/influxdb3/enterprise/v3/influxdb3-enterprise-openapi.yaml b/api-docs/influxdb3/enterprise/v3/influxdb3-enterprise-openapi.yaml new file mode 100644 index 000000000..5ff481f9d --- /dev/null +++ b/api-docs/influxdb3/enterprise/v3/influxdb3-enterprise-openapi.yaml @@ -0,0 +1,3799 @@ +openapi: 3.0.3 +info: + title: InfluxDB 3 Enterprise API Service + description: | + The InfluxDB HTTP API for InfluxDB 3 Enterprise provides a programmatic interface for + interacting with InfluxDB 3 Enterprise databases and resources. + Use this API to: + + - Write data to InfluxDB 3 Enterprise databases + - Query data using SQL or InfluxQL + - Process data using Processing engine plugins + - Manage databases, tables, and Processing engine triggers + - Perform administrative tasks and access system information + + The API includes endpoints under the following paths: + - `/api/v3`: InfluxDB 3 Enterprise native endpoints + - `/`: Compatibility endpoints for InfluxDB v1 workloads and clients + - `/api/v2/write`: Compatibility endpoint for InfluxDB v2 workloads and clients + + [Download the OpenAPI specification](/openapi/influxdb3-enterprise-openapi.yaml) + version: v3.8.0 + license: + name: MIT + url: https://opensource.org/licenses/MIT + contact: + name: InfluxData + url: https://www.influxdata.com + email: support@influxdata.com + x-source-hash: sha256:1259b96096eab6c8dbf3f76c974924f124e9b3e08eedc6b0c9a66d3108857c52 +servers: + - url: https://{baseurl} + description: InfluxDB 3 Enterprise API URL + variables: + baseurl: + enum: + - localhost:8181 + default: localhost:8181 + description: InfluxDB 3 Enterprise URL +security: + - BearerAuthentication: [] + - TokenAuthentication: [] + - BasicAuthentication: [] + - QuerystringAuthentication: [] +tags: + - name: Authentication + description: | + Depending on your workflow, use one of the following schemes to authenticate to the InfluxDB 3 API: + + | Authentication scheme | Works with | + |:-------------------|:-----------| + | [Bearer authentication](#section/Authentication/BearerAuthentication) | All endpoints | + | [Token authentication](#section/Authentication/TokenAuthentication) | v1, v2 endpoints | + | [Basic authentication](#section/Authentication/BasicAuthentication) | v1 endpoints | + | [Querystring authentication](#section/Authentication/QuerystringAuthentication) | v1 endpoints | + + x-traitTag: true + x-related: + - title: Authenticate v1 API requests + href: /influxdb3/enterprise/guides/api-compatibility/v1/ + - title: Manage tokens + href: /influxdb3/enterprise/admin/tokens/ + - name: Cache data + description: |- + Manage the in-memory cache. + + #### Distinct Value Cache + + The Distinct Value Cache (DVC) lets you cache distinct + values of one or more columns in a table, improving the performance of + queries that return distinct tag and field values. + + The DVC is an in-memory cache that stores distinct values for specific columns + in a table. When you create an DVC, you can specify what columns' distinct + values to cache, the maximum number of distinct value combinations to cache, and + the maximum age of cached values. A DVC is associated with a table, which can + have multiple DVCs. + + #### Last value cache + + The Last Value Cache (LVC) lets you cache the most recent + values for specific fields in a table, improving the performance of queries that + return the most recent value of a field for specific series or the last N values + of a field. + + The LVC is an in-memory cache that stores the last N number of values for + specific fields of series in a table. When you create an LVC, you can specify + what fields to cache, what tags to use to identify each series, and the + number of values to cache for each unique series. + An LVC is associated with a table, which can have multiple LVCs. + x-related: + - title: Manage the Distinct Value Cache + href: /influxdb3/enterprise/admin/distinct-value-cache/ + - title: Manage the Last Value Cache + href: /influxdb3/enterprise/admin/last-value-cache/ + - name: Compatibility endpoints + description: > + InfluxDB 3 provides compatibility endpoints for InfluxDB 1.x and InfluxDB 2.x workloads and clients. + + + ### Write data using v1- or v2-compatible endpoints + + + - [`/api/v2/write` endpoint](#operation/PostV2Write) + for InfluxDB v2 clients and when you bring existing InfluxDB v2 write workloads to InfluxDB 3. + - [`/write` endpoint](#operation/PostV1Write) for InfluxDB v1 clients and when you bring existing InfluxDB v1 + write workloads to InfluxDB 3. + + + For new workloads, use the [`/api/v3/write_lp` endpoint](#operation/PostWriteLP). + + + All endpoints accept the same line protocol format. + + + ### Query data + + + Use the HTTP [`/query`](#operation/GetV1ExecuteQuery) endpoint for InfluxDB v1 clients and v1 query workloads + using InfluxQL. + + + For new workloads, use one of the following: + + + - HTTP [`/api/v3/query_sql` endpoint](#operation/GetExecuteQuerySQL) for new query workloads using SQL. + + - HTTP [`/api/v3/query_influxql` endpoint](#operation/GetExecuteInfluxQLQuery) for new query workloads using + InfluxQL. + + - Flight SQL and InfluxDB 3 _Flight+gRPC_ APIs for querying with SQL or InfluxQL. For more information about using + Flight APIs, see [InfluxDB 3 client + libraries](https://github.com/InfluxCommunity?q=influxdb3&type=public&language=&sort=). + + + ### Server information + + + Server information endpoints such as `/health` and `metrics` are compatible with InfluxDB 1.x and InfluxDB 2.x + clients. + x-related: + - title: Use compatibility APIs to write data + href: /influxdb3/enterprise/write-data/http-api/compatibility-apis/ + - name: Database + description: Manage databases + - description: > + Most InfluxDB API endpoints require parameters in the request--for example, specifying the database to use. + + + ### Common parameters + + + The following table shows common parameters used by many InfluxDB API endpoints. + + Many endpoints may require other parameters in the query string or in the + + request body that perform functions specific to those endpoints. + + + | Query parameter | Value type | Description | + + |:------------------------ |:--------------------- |:-------------------------------------------| + + | `db` | string | The database name | + + + InfluxDB HTTP API endpoints use standard HTTP request and response headers. + + The following table shows common headers used by many InfluxDB API endpoints. + + Some endpoints may use other headers that perform functions more specific to those endpoints--for example, + + the write endpoints accept the `Content-Encoding` header to indicate that line protocol is compressed in the + request body. + + + | Header | Value type | Description | + + |:------------------------ |:--------------------- |:-------------------------------------------| + + | `Accept` | string | The content type that the client can understand. | + + | `Authorization` | string | The authorization scheme and credential. | + + | `Content-Length` | integer | The size of the entity-body, in bytes. | + + | `Content-Type` | string | The format of the data in the request body. | + name: Headers and parameters + x-traitTag: true + - name: Processing engine + description: > + Manage Processing engine triggers, test plugins, and send requests to trigger On Request plugins. + + + InfluxDB 3 Enterprise provides the InfluxDB 3 processing engine, an embedded Python VM that can dynamically load + and trigger Python plugins in response to events in your database. + + Use Processing engine plugins and triggers to run code and perform tasks for different database events. + + + To get started with the processing engine, see the [Processing engine and Python + plugins](/influxdb3/enterprise/processing-engine/) guide. + x-related: + - title: Processing engine and Python plugins + href: /influxdb3/enterprise/plugins/ + - name: Query data + description: Query data using SQL or InfluxQL + x-related: + - title: Use the InfluxDB v1 HTTP query API and InfluxQL to query data + href: /influxdb3/enterprise/query-data/execute-queries/influxdb-v1-api/ + - name: Quick start + description: > + 1. [Create an admin token](#section/Authentication) to authorize API requests. + + ```bash + curl -X POST "http://localhost:8181/api/v3/configure/token/admin" + ``` + 2. [Check the status](#section/Server-information) of the InfluxDB server. + + ```bash + curl "http://localhost:8181/health" \ + --header "Authorization: Bearer ADMIN_TOKEN" + ``` + + 3. [Write data](#operation/PostWriteLP) to InfluxDB. + + ```bash + curl "http://localhost:8181/api/v3/write_lp?db=sensors&precision=auto" + --header "Authorization: Bearer ADMIN_TOKEN" \ + --data-raw "home,room=Kitchen temp=72.0 + home,room=Living\ room temp=71.5" + ``` + + If all data is written, the response is `204 No Content`. + + 4. [Query data](#operation/GetExecuteQuerySQL) from InfluxDB. + + ```bash + curl -G "http://localhost:8181/api/v3/query_sql" \ + --header "Authorization: Bearer ADMIN_TOKEN" \ + --data-urlencode "db=sensors" \ + --data-urlencode "q=SELECT * FROM home WHERE room='Living room'" \ + --data-urlencode "format=jsonl" + ``` + + Output: + + ```jsonl + {"room":"Living room","temp":71.5,"time":"2025-02-25T20:19:34.984098"} + ``` + + For more information about using InfluxDB 3 Enterprise, see the [Get started](/influxdb3/enterprise/get-started/) + guide. + x-traitTag: true + - name: Server information + description: Retrieve server metrics, status, and version information + - name: Table + description: Manage table schemas and data + - name: Token + description: Manage tokens for authentication and authorization + - name: Write data + description: | + Write data to InfluxDB 3 using line protocol format. + + #### Timestamp precision across write APIs + + InfluxDB 3 provides multiple write endpoints for compatibility with different InfluxDB versions. + The following table compares timestamp precision support across v1, v2, and v3 write APIs: + + | Precision | v1 (`/write`) | v2 (`/api/v2/write`) | v3 (`/api/v3/write_lp`) | + |-----------|---------------|----------------------|-------------------------| + | **Auto detection** | ❌ No | ❌ No | ✅ `auto` (default) | + | **Seconds** | ✅ `s` | ✅ `s` | ✅ `second` | + | **Milliseconds** | ✅ `ms` | ✅ `ms` | ✅ `millisecond` | + | **Microseconds** | ✅ `u` or `µ` | ✅ `us` | ✅ `microsecond` | + | **Nanoseconds** | ✅ `ns` | ✅ `ns` | ✅ `nanosecond` | + | **Default** | Nanosecond | Nanosecond | **Auto** (guessed) | + + All timestamps are stored internally as nanoseconds. +paths: + /api/v1/health: + get: + operationId: GetHealthV1 + summary: Health check (v1) + description: | + Checks the status of the service. + + Returns `OK` if the service is running. This endpoint does not return version information. + Use the [`/ping`](#operation/GetPing) endpoint to retrieve version details. + + > **Note**: This endpoint requires authentication by default in InfluxDB 3 Enterprise. + responses: + "200": + description: Service is running. Returns `OK`. + content: + text/plain: + schema: + type: string + example: OK + "401": + description: Unauthorized. Authentication is required. + "500": + description: Service is unavailable. + tags: + - Server information + - Compatibility endpoints + /api/v2/write: + post: + operationId: PostV2Write + responses: + "204": + description: Success ("No Content"). All data in the batch is written and queryable. + headers: + cluster-uuid: + $ref: "#/components/headers/ClusterUUID" + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "413": + description: Request entity too large. + summary: Write line protocol (v2-compatible) + description: > + Writes line protocol to the specified database. + + + This endpoint provides backward compatibility for InfluxDB 2.x write workloads using tools such as InfluxDB 2.x + client libraries, the Telegraf `outputs.influxdb_v2` output plugin, or third-party tools. + + + Use this endpoint to send data in [line protocol](/influxdb3/enterprise/reference/syntax/line-protocol/) format + to InfluxDB. + + Use query parameters to specify options for writing data. + + + #### Related + + + - [Use compatibility APIs to write data](/influxdb3/enterprise/write-data/http-api/compatibility-apis/) + parameters: + - name: Content-Type + in: header + description: | + The content type of the request payload. + schema: + $ref: "#/components/schemas/LineProtocol" + required: false + - description: | + The compression applied to the line protocol in the request payload. + To send a gzip payload, pass `Content-Encoding: gzip` header. + in: header + name: Content-Encoding + schema: + default: identity + description: | + Content coding. + Use `gzip` for compressed data or `identity` for unmodified, uncompressed data. + enum: + - gzip + - identity + type: string + - description: | + The size of the entity-body, in bytes, sent to InfluxDB. + in: header + name: Content-Length + schema: + description: The length in decimal number of octets. + type: integer + - description: | + The content type that the client can understand. + Writes only return a response body if they fail (partially or completely)--for example, + due to a syntax problem or type mismatch. + in: header + name: Accept + schema: + default: application/json + description: Error content type. + enum: + - application/json + type: string + - name: bucket + in: query + required: true + schema: + type: string + description: |- + A database name. + InfluxDB creates the database if it doesn't already exist, and then + writes all points in the batch to the database. + + This parameter is named `bucket` for compatibility with InfluxDB v2 client libraries. + - name: accept_partial + in: query + required: false + schema: + $ref: "#/components/schemas/AcceptPartial" + - $ref: "#/components/parameters/compatibilityPrecisionParam" + requestBody: + $ref: "#/components/requestBodies/lineProtocolRequestBody" + tags: + - Compatibility endpoints + - Write data + /api/v3/configure/database: + delete: + operationId: DeleteConfigureDatabase + parameters: + - $ref: "#/components/parameters/db" + - name: data_only + in: query + required: false + schema: + type: boolean + default: false + description: | + Delete only data while preserving the database schema and all associated resources + (tokens, triggers, last value caches, distinct value caches, processing engine configurations). + When `false` (default), the entire database is deleted. + - name: remove_tables + in: query + required: false + schema: + type: boolean + default: false + description: | + Used with `data_only=true` to remove table resources (caches) while preserving + database-level resources (tokens, triggers, processing engine configurations). + Has no effect when `data_only=false`. + - name: hard_delete_at + in: query + required: false + schema: + type: string + format: date-time + description: |- + Schedule the database for hard deletion at the specified time. + If not provided, the database will be soft deleted. + Use ISO 8601 date-time format (for example, "2025-12-31T23:59:59Z"). + + #### Deleting a database cannot be undone + + Deleting a database is a destructive action. + Once a database is deleted, data stored in that database cannot be recovered. + + + Also accepts special string values: + - `now` — hard delete immediately + - `never` — soft delete only (default behavior) + - `default` — use the system default hard deletion time + responses: + "200": + description: Success. Database deleted. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + summary: Delete a database + description: | + Soft deletes a database. + The database is scheduled for deletion and unavailable for querying. + Use the `hard_delete_at` parameter to schedule a hard deletion. + Use the `data_only` parameter to delete data while preserving the database schema and resources. + tags: + - Database + get: + operationId: GetConfigureDatabase + responses: + "200": + description: Success. The response body contains the list of databases. + content: + application/json: + schema: + $ref: "#/components/schemas/ShowDatabasesResponse" + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + summary: List databases + description: Retrieves a list of databases. + parameters: + - $ref: "#/components/parameters/formatRequired" + - name: show_deleted + in: query + required: false + schema: + type: boolean + default: false + description: | + Include soft-deleted databases in the response. + By default, only active databases are returned. + tags: + - Database + post: + operationId: PostConfigureDatabase + responses: + "200": + description: Success. Database created. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "409": + description: Database already exists. + summary: Create a database + description: Creates a new database in the system. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateDatabaseRequest" + tags: + - Database + put: + operationId: update_database + responses: + "200": + description: Success. The database has been updated. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + summary: Update a database + description: | + Updates database configuration, such as retention period. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateDatabaseRequest" + tags: + - Database + /api/v3/configure/database/retention_period: + delete: + operationId: DeleteDatabaseRetentionPeriod + summary: Remove database retention period + description: | + Removes the retention period from a database, setting it to infinite retention. + parameters: + - $ref: "#/components/parameters/db" + responses: + "204": + description: Success. The database retention period has been removed. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + tags: + - Database + /api/v3/configure/distinct_cache: + delete: + operationId: DeleteConfigureDistinctCache + responses: + "200": + description: Success. The distinct cache has been deleted. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Cache not found. + summary: Delete distinct cache + description: Deletes a distinct cache. + parameters: + - $ref: "#/components/parameters/db" + - name: table + in: query + required: true + schema: + type: string + description: The name of the table containing the distinct cache. + - name: name + in: query + required: true + schema: + type: string + description: The name of the distinct cache to delete. + tags: + - Cache data + - Table + post: + operationId: PostConfigureDistinctCache + responses: + "201": + description: Success. The distinct cache has been created. + "400": + description: > + Bad request. + + + The server responds with status `400` if the request would overwrite an existing cache with a different + configuration. + "409": + description: Conflict. A distinct cache with this configuration already exists. + summary: Create distinct cache + description: Creates a distinct cache for a table. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DistinctCacheCreateRequest" + tags: + - Cache data + - Table + /api/v3/configure/last_cache: + delete: + operationId: DeleteConfigureLastCache + responses: + "200": + description: Success. The last cache has been deleted. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Cache not found. + summary: Delete last cache + description: Deletes a last cache. + parameters: + - $ref: "#/components/parameters/db" + - name: table + in: query + required: true + schema: + type: string + description: The name of the table containing the last cache. + - name: name + in: query + required: true + schema: + type: string + description: The name of the last cache to delete. + tags: + - Cache data + - Table + post: + operationId: PostConfigureLastCache + responses: + "201": + description: Success. Last cache created. + "400": + description: Bad request. A cache with this name already exists or the request is malformed. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Cache not found. + summary: Create last cache + description: Creates a last cache for a table. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/LastCacheCreateRequest" + tags: + - Cache data + - Table + /api/v3/configure/plugin_environment/install_packages: + post: + operationId: PostInstallPluginPackages + summary: Install plugin packages + description: |- + Installs the specified Python packages into the processing engine plugin environment. + + This endpoint is synchronous and blocks until the packages are installed. + parameters: + - $ref: "#/components/parameters/ContentType" + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + packages: + type: array + items: + type: string + description: | + A list of Python package names to install. + Can include version specifiers (e.g., "scipy==1.9.0"). + example: + - influxdb3-python + - scipy + - pandas==1.5.0 + - requests + required: + - packages + example: + packages: + - influxdb3-python + - scipy + - pandas==1.5.0 + - requests + responses: + "200": + description: Success. The packages are installed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + tags: + - Processing engine + /api/v3/configure/plugin_environment/install_requirements: + post: + operationId: PostInstallPluginRequirements + summary: Install plugin requirements + description: > + Installs requirements from a requirements file (also known as a "pip requirements file") into the processing + engine plugin environment. + + + This endpoint is synchronous and blocks until the requirements are installed. + + + ### Related + + + - [Processing engine and Python plugins](/influxdb3/enterprise/plugins/) + + - [Python requirements file format](https://pip.pypa.io/en/stable/reference/requirements-file-format/) + parameters: + - $ref: "#/components/parameters/ContentType" + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + requirements_location: + type: string + description: | + The path to the requirements file containing Python packages to install. + Can be a relative path (relative to the plugin directory) or an absolute path. + example: requirements.txt + required: + - requirements_location + example: + requirements_location: requirements.txt + responses: + "200": + description: Success. The requirements have been installed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + tags: + - Processing engine + /api/v3/configure/processing_engine_trigger: + post: + operationId: PostConfigureProcessingEngineTrigger + summary: Create processing engine trigger + description: Creates a processing engine trigger with the specified plugin file and trigger specification. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessingEngineTriggerRequest" + examples: + schedule_cron: + summary: Schedule trigger using cron + description: > + In `"cron:CRON_EXPRESSION"`, `CRON_EXPRESSION` uses extended 6-field cron format. + + The cron expression `0 0 6 * * 1-5` means the trigger will run at 6:00 AM every weekday (Monday to + Friday). + value: + db: DATABASE_NAME + plugin_filename: schedule.py + trigger_name: schedule_cron_trigger + trigger_specification: cron:0 0 6 * * 1-5 + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + schedule_every: + summary: Schedule trigger using interval + description: | + In `"every:DURATION"`, `DURATION` specifies the interval between trigger executions. + The duration `1h` means the trigger will run every hour. + value: + db: mydb + plugin_filename: schedule.py + trigger_name: schedule_every_trigger + trigger_specification: every:1h + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + schedule_every_seconds: + summary: Schedule trigger using seconds interval + description: | + Example of scheduling a trigger to run every 30 seconds. + value: + db: mydb + plugin_filename: schedule.py + trigger_name: schedule_every_30s_trigger + trigger_specification: every:30s + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + schedule_every_minutes: + summary: Schedule trigger using minutes interval + description: | + Example of scheduling a trigger to run every 5 minutes. + value: + db: mydb + plugin_filename: schedule.py + trigger_name: schedule_every_5m_trigger + trigger_specification: every:5m + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + all_tables: + summary: All tables trigger example + description: | + Trigger that fires on write events to any table in the database. + value: + db: mydb + plugin_filename: all_tables.py + trigger_name: all_tables_trigger + trigger_specification: all_tables + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + table_specific: + summary: Table-specific trigger example + description: | + Trigger that fires on write events to a specific table. + value: + db: mydb + plugin_filename: table.py + trigger_name: table_trigger + trigger_specification: table:sensors + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + api_request: + summary: On-demand request trigger example + description: | + Creates an HTTP endpoint `/api/v3/engine/hello-world` for manual invocation. + value: + db: mydb + plugin_filename: request.py + trigger_name: hello_world_trigger + trigger_specification: request:hello-world + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + cron_friday_afternoon: + summary: Cron trigger for Friday afternoons + description: | + Example of a cron trigger that runs every Friday at 2:30 PM. + value: + db: reports + plugin_filename: weekly_report.py + trigger_name: friday_report_trigger + trigger_specification: cron:0 30 14 * * 5 + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + cron_monthly: + summary: Cron trigger for monthly execution + description: | + Example of a cron trigger that runs on the first day of every month at midnight. + value: + db: monthly_data + plugin_filename: monthly_cleanup.py + trigger_name: monthly_cleanup_trigger + trigger_specification: cron:0 0 0 1 * * + disabled: false + trigger_settings: + run_async: false + error_behavior: Log + responses: + "200": + description: Success. Processing engine trigger created. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Trigger not found. + tags: + - Processing engine + delete: + operationId: DeleteConfigureProcessingEngineTrigger + summary: Delete processing engine trigger + description: Deletes a processing engine trigger. + parameters: + - $ref: "#/components/parameters/db" + - name: trigger_name + in: query + required: true + schema: + type: string + - name: force + in: query + required: false + schema: + type: boolean + default: false + description: | + Force deletion of the trigger even if it has active executions. + By default, deletion fails if the trigger is currently executing. + responses: + "200": + description: Success. The processing engine trigger has been deleted. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Trigger not found. + tags: + - Processing engine + /api/v3/configure/processing_engine_trigger/disable: + post: + operationId: PostDisableProcessingEngineTrigger + summary: Disable processing engine trigger + description: Disables a processing engine trigger. + parameters: + - name: db + in: query + required: true + schema: + type: string + description: The database name. + - name: trigger_name + in: query + required: true + schema: + type: string + description: The name of the trigger. + responses: + "200": + description: Success. The processing engine trigger has been disabled. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Trigger not found. + tags: + - Processing engine + /api/v3/configure/processing_engine_trigger/enable: + post: + operationId: PostEnableProcessingEngineTrigger + summary: Enable processing engine trigger + description: Enables a processing engine trigger. + parameters: + - name: db + in: query + required: true + schema: + type: string + description: The database name. + - name: trigger_name + in: query + required: true + schema: + type: string + description: The name of the trigger. + responses: + "200": + description: Success. The processing engine trigger is enabled. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Trigger not found. + tags: + - Processing engine + /api/v3/configure/table: + delete: + operationId: DeleteConfigureTable + parameters: + - $ref: "#/components/parameters/db" + - name: table + in: query + required: true + schema: + type: string + - name: data_only + in: query + required: false + schema: + type: boolean + default: false + description: | + Delete only data while preserving the table schema and all associated resources + (last value caches, distinct value caches). + When `false` (default), the entire table is deleted. + - name: hard_delete_at + in: query + required: false + schema: + type: string + format: date-time + description: |- + Schedule the table for hard deletion at the specified time. + If not provided, the table will be soft deleted. + Use ISO 8601 format (for example, "2025-12-31T23:59:59Z"). + + + Also accepts special string values: + - `now` — hard delete immediately + - `never` — soft delete only (default behavior) + - `default` — use the system default hard deletion time + responses: + "200": + description: Success (no content). The table has been deleted. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Table not found. + summary: Delete a table + description: | + Soft deletes a table. + The table is scheduled for deletion and unavailable for querying. + Use the `hard_delete_at` parameter to schedule a hard deletion. + Use the `data_only` parameter to delete data while preserving the table schema and resources. + + #### Deleting a table cannot be undone + + Deleting a table is a destructive action. + Once a table is deleted, data stored in that table cannot be recovered. + tags: + - Table + post: + operationId: PostConfigureTable + responses: + "200": + description: Success. The table has been created. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database not found. + summary: Create a table + description: Creates a new table within a database. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateTableRequest" + tags: + - Table + put: + operationId: PatchConfigureTable + responses: + "200": + description: Success. The table has been updated. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Table not found. + summary: Update a table + description: | + Updates table configuration, such as retention period. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateTableRequest" + tags: + - Table + x-enterprise-only: true + /api/v3/configure/token: + delete: + operationId: DeleteToken + parameters: + - name: token_name + in: query + required: true + schema: + type: string + description: The name of the token to delete. + responses: + "200": + description: Success. The token has been deleted. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Token not found. + summary: Delete token + description: | + Deletes a token. + tags: + - Authentication + - Token + /api/v3/configure/token/admin: + post: + operationId: PostCreateAdminToken + responses: + "201": + description: | + Success. The admin token has been created. + The response body contains the token string and metadata. + content: + application/json: + schema: + $ref: "#/components/schemas/AdminTokenObject" + "401": + $ref: "#/components/responses/Unauthorized" + summary: Create admin token + description: | + Creates an admin token. + An admin token is a special type of token that has full access to all resources in the system. + tags: + - Authentication + - Token + /api/v3/configure/token/admin/regenerate: + post: + operationId: PostRegenerateAdminToken + summary: Regenerate admin token + description: | + Regenerates an admin token and revokes the previous token with the same name. + parameters: [] + responses: + "201": + description: Success. The admin token has been regenerated. + content: + application/json: + schema: + $ref: "#/components/schemas/AdminTokenObject" + "401": + $ref: "#/components/responses/Unauthorized" + tags: + - Authentication + - Token + /api/v3/configure/token/named_admin: + post: + operationId: PostCreateNamedAdminToken + responses: + "201": + description: | + Success. The named admin token has been created. + The response body contains the token string and metadata. + content: + application/json: + schema: + $ref: "#/components/schemas/AdminTokenObject" + "401": + $ref: "#/components/responses/Unauthorized" + "409": + description: A token with this name already exists. + summary: Create named admin token + description: | + Creates a named admin token. + A named admin token is a special type of admin token with a custom name for identification and management. + tags: + - Authentication + - Token + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + token_name: + type: string + description: The name for the admin token. + expiry_secs: + type: integer + description: Optional expiration time in seconds. If not provided, the token does not expire. + nullable: true + required: + - token_name + /api/v3/engine/{request_path}: + get: + operationId: GetProcessingEnginePluginRequest + responses: + "200": + description: Success. The plugin request has been executed. + "400": + description: Malformed request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not found. + "500": + description: Processing failure. + summary: On Request processing engine plugin request + description: > + Executes the On Request processing engine plugin specified in the trigger's `plugin_filename`. + + The request can include request headers, query string parameters, and a request body, which InfluxDB passes to + the plugin. + + + An On Request plugin implements the following signature: + + + ```python + + def process_request(influxdb3_local, query_parameters, request_headers, request_body, args=None) + + ``` + + + The response depends on the plugin implementation. + tags: + - Processing engine + post: + operationId: PostProcessingEnginePluginRequest + responses: + "200": + description: Success. The plugin request has been executed. + "400": + description: Malformed request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not found. + "500": + description: Processing failure. + summary: On Request processing engine plugin request + description: > + Executes the On Request processing engine plugin specified in the trigger's `plugin_filename`. + + The request can include request headers, query string parameters, and a request body, which InfluxDB passes to + the plugin. + + + An On Request plugin implements the following signature: + + + ```python + + def process_request(influxdb3_local, query_parameters, request_headers, request_body, args=None) + + ``` + + + The response depends on the plugin implementation. + parameters: + - $ref: "#/components/parameters/ContentType" + requestBody: + required: false + content: + application/json: + schema: + type: object + additionalProperties: true + tags: + - Processing engine + parameters: + - name: request_path + description: | + The path configured in the request trigger specification for the plugin. + + For example, if you define a trigger with the following: + + ```json + trigger_specification: "request:hello-world" + ``` + + then, the HTTP API exposes the following plugin endpoint: + + ``` + /api/v3/engine/hello-world + ``` + in: path + required: true + schema: + type: string + /api/v3/enterprise/configure/file_index: + post: + operationId: configure_file_index_create + summary: Create a file index + description: >- + Creates a file index for a database or table. + + + A file index improves query performance by indexing data files based on specified columns, enabling the query + engine to skip irrelevant files during query execution. + + + This endpoint is only available in InfluxDB 3 Enterprise. + x-enterprise-only: true + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/FileIndexCreateRequest" + responses: + "200": + description: Success. The file index has been created. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database or table not found. + tags: + - Database + - Table + delete: + operationId: configure_file_index_delete + summary: Delete a file index + description: |- + Deletes a file index from a database or table. + + This endpoint is only available in InfluxDB 3 Enterprise. + x-enterprise-only: true + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/FileIndexDeleteRequest" + responses: + "200": + description: Success. The file index has been deleted. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database, table, or file index not found. + tags: + - Database + - Table + /api/v3/enterprise/configure/node/stop: + post: + operationId: stop_node + summary: Mark a node as stopped + description: >- + Marks a node as stopped in the catalog, freeing up the licensed cores it was using for other nodes. + + + Use this endpoint after you have already stopped the physical instance (for example, using `kill` or stopping + the container). This endpoint does not shut down the running process — you must stop the instance first. + + + When the node is marked as stopped: + + 1. Licensed cores from the stopped node are freed for reuse + + 2. Other nodes in the cluster see the update after their catalog sync interval + + + This endpoint is only available in InfluxDB 3 Enterprise. + + + #### Related + + + - [influxdb3 stop node](/influxdb3/enterprise/reference/cli/influxdb3/stop/node/) + x-enterprise-only: true + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/StopNodeRequest" + responses: + "200": + description: Success. The node has been marked as stopped. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Node not found. + tags: + - Server information + /api/v3/enterprise/configure/table/retention_period: + post: + operationId: create_or_update_retention_period_for_table + summary: Set table retention period + description: >- + Sets or updates the retention period for a specific table. + + + Use this endpoint to control how long data in a table is retained independently of the database-level retention + period. + + + This endpoint is only available in InfluxDB 3 Enterprise. + + + #### Related + + + - [influxdb3 update table](/influxdb3/enterprise/reference/cli/influxdb3/update/table/) + x-enterprise-only: true + parameters: + - name: db + in: query + required: true + schema: + type: string + description: The database name. + - name: table + in: query + required: true + schema: + type: string + description: The table name. + - name: duration + in: query + required: true + schema: + type: string + description: The retention period as a human-readable duration (for example, "30d", "24h", "1y"). + responses: + "204": + description: Success. The table retention period has been set. + "400": + description: Bad request. Invalid duration format. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database or table not found. + tags: + - Table + delete: + operationId: delete_retention_period_for_table + summary: Clear table retention period + description: >- + Removes the retention period from a specific table, reverting to the database-level retention period (or + infinite retention if no database-level retention is set). + + + This endpoint is only available in InfluxDB 3 Enterprise. + + + #### Related + + + - [influxdb3 update table](/influxdb3/enterprise/reference/cli/influxdb3/update/table/) + x-enterprise-only: true + parameters: + - name: db + in: query + required: true + schema: + type: string + description: The database name. + - name: table + in: query + required: true + schema: + type: string + description: The table name. + responses: + "204": + description: Success. The table retention period has been cleared. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Database or table not found. + tags: + - Table + /api/v3/enterprise/configure/token: + post: + operationId: PostCreateResourceToken + summary: Create a resource token + description: | + Creates a resource (fine-grained permissions) token. + A resource token is a token that has access to specific resources in the system. + + This endpoint is only available in InfluxDB 3 Enterprise. + responses: + "201": + description: | + Success. The resource token has been created. + The response body contains the token string and metadata. + content: + application/json: + schema: + $ref: "#/components/schemas/ResourceTokenObject" + "401": + $ref: "#/components/responses/Unauthorized" + tags: + - Authentication + - Token + x-enterprise-only: true + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateTokenWithPermissionsRequest" + /api/v3/plugin_test/schedule: + post: + operationId: PostTestSchedulingPlugin + responses: + "200": + description: Success. The plugin test has been executed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not enabled. + summary: Test scheduling plugin + description: Executes a test of a scheduling plugin. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/SchedulePluginTestRequest" + tags: + - Processing engine + /api/v3/plugin_test/wal: + post: + operationId: PostTestWALPlugin + responses: + "200": + description: Success. The plugin test has been executed. + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "404": + description: Plugin not enabled. + summary: Test WAL plugin + description: Executes a test of a write-ahead logging (WAL) plugin. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/WALPluginTestRequest" + tags: + - Processing engine + /api/v3/plugins/directory: + put: + operationId: PutPluginDirectory + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PluginDirectoryRequest" + responses: + "200": + description: Success. The plugin directory has been updated. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Forbidden. Admin token required. + "500": + description: Plugin not found. The `plugin_name` does not match any registered trigger. + summary: Update a multi-file plugin directory + description: | + Replaces all files in a multi-file plugin directory. The + `plugin_name` must match a registered trigger name. Each entry in + the `files` array specifies a `relative_path` and `content`—the + server writes them into the trigger's plugin directory. + + Use this endpoint to update multi-file plugins (directories with + `__init__.py` and supporting modules). For single-file plugins, + use `PUT /api/v3/plugins/files` instead. + tags: + - Processing engine + x-security-note: Requires an admin token + /api/v3/plugins/files: + post: + operationId: create_plugin_file + summary: Create a plugin file + description: | + Creates a single plugin file in the plugin directory. Writes the + `content` to a file named after `plugin_name`. Does not require an + existing trigger—use this to upload plugin files before creating + triggers that reference them. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PluginFileRequest" + responses: + "200": + description: Success. The plugin file has been created. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Forbidden. Admin token required. + tags: + - Processing engine + x-security-note: Requires an admin token + put: + operationId: PutPluginFile + summary: Update a plugin file + description: | + Updates a single plugin file for an existing trigger. The + `plugin_name` must match a registered trigger name—the server + resolves the trigger's `plugin_filename` and overwrites that file + with the provided `content`. + + To upload a new plugin file before creating a trigger, use + `POST /api/v3/plugins/files` instead. To update a multi-file + plugin directory, use `PUT /api/v3/plugins/directory`. + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/PluginFileRequest" + responses: + "200": + description: Success. The plugin file has been updated. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Forbidden. Admin token required. + "500": + description: Plugin not found. The `plugin_name` does not match any registered trigger. + tags: + - Processing engine + x-security-note: Requires an admin token + /api/v3/query_influxql: + get: + operationId: GetExecuteInfluxQLQuery + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query + description: Executes an InfluxQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/dbQueryParam" + - name: q + in: query + required: true + schema: + type: string + - name: format + in: query + required: false + schema: + type: string + - $ref: "#/components/parameters/AcceptQueryHeader" + - name: params + in: query + required: false + schema: + type: string + description: JSON-encoded query parameters. Use this to pass bind parameters to parameterized queries. + description: JSON-encoded query parameters for parameterized queries. + tags: + - Query data + post: + operationId: PostExecuteQueryInfluxQL + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query + description: Executes an InfluxQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/AcceptQueryHeader" + - $ref: "#/components/parameters/ContentType" + requestBody: + $ref: "#/components/requestBodies/queryRequestBody" + tags: + - Query data + /api/v3/query_sql: + get: + operationId: GetExecuteQuerySQL + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + example: + results: + - series: + - name: mytable + columns: + - time + - value + values: + - - "2024-02-02T12:00:00Z" + - 42 + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute SQL query + description: Executes an SQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/db" + - $ref: "#/components/parameters/querySqlParam" + - $ref: "#/components/parameters/format" + - $ref: "#/components/parameters/AcceptQueryHeader" + - $ref: "#/components/parameters/ContentType" + - name: params + in: query + required: false + schema: + type: string + description: JSON-encoded query parameters. Use this to pass bind parameters to parameterized queries. + description: JSON-encoded query parameters for parameterized queries. + tags: + - Query data + post: + operationId: PostExecuteQuerySQL + responses: + "200": + description: Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + text/csv: + schema: + type: string + application/vnd.apache.parquet: + schema: + type: string + application/jsonl: + schema: + type: string + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute SQL query + description: Executes an SQL query to retrieve data from the specified database. + parameters: + - $ref: "#/components/parameters/AcceptQueryHeader" + - $ref: "#/components/parameters/ContentType" + requestBody: + $ref: "#/components/requestBodies/queryRequestBody" + tags: + - Query data + /api/v3/write_lp: + post: + operationId: PostWriteLP + parameters: + - $ref: "#/components/parameters/dbWriteParam" + - $ref: "#/components/parameters/accept_partial" + - $ref: "#/components/parameters/precisionParam" + - name: no_sync + in: query + schema: + $ref: "#/components/schemas/NoSync" + - name: Content-Type + in: header + description: | + The content type of the request payload. + schema: + $ref: "#/components/schemas/LineProtocol" + required: false + - name: Accept + in: header + description: | + The content type that the client can understand. + Writes only return a response body if they fail (partially or completely)--for example, + due to a syntax problem or type mismatch. + schema: + type: string + default: application/json + enum: + - application/json + required: false + - $ref: "#/components/parameters/ContentEncoding" + - $ref: "#/components/parameters/ContentLength" + responses: + "204": + description: Success ("No Content"). All data in the batch is written and queryable. + headers: + cluster-uuid: + $ref: "#/components/headers/ClusterUUID" + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "413": + description: Request entity too large. + "422": + description: Unprocessable entity. + summary: Write line protocol + description: > + Writes line protocol to the specified database. + + + This is the native InfluxDB 3 Enterprise write endpoint that provides enhanced control + + over write behavior with advanced parameters for high-performance and fault-tolerant operations. + + + Use this endpoint to send data in [line protocol](/influxdb3/enterprise/reference/syntax/line-protocol/) format + to InfluxDB. + + Use query parameters to specify options for writing data. + + + #### Features + + + - **Partial writes**: Use `accept_partial=true` to allow partial success when some lines in a batch fail + + - **Asynchronous writes**: Use `no_sync=true` to skip waiting for WAL synchronization, allowing faster response + times but sacrificing durability guarantees + + - **Flexible precision**: Automatic timestamp precision detection with `precision=auto` (default) + + + #### Auto precision detection + + + When you use `precision=auto` or omit the precision parameter, InfluxDB 3 automatically detects + + the timestamp precision based on the magnitude of the timestamp value: + + + - Timestamps < 5e9 → Second precision (multiplied by 1,000,000,000 to convert to nanoseconds) + + - Timestamps < 5e12 → Millisecond precision (multiplied by 1,000,000) + + - Timestamps < 5e15 → Microsecond precision (multiplied by 1,000) + + - Larger timestamps → Nanosecond precision (no conversion needed) + + + #### Related + + + - [Use the InfluxDB v3 write_lp API to write data](/influxdb3/enterprise/write-data/http-api/v3-write-lp/) + requestBody: + $ref: "#/components/requestBodies/lineProtocolRequestBody" + tags: + - Write data + x-codeSamples: + - label: cURL - Basic write + lang: Shell + source: | + curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01 usage=85.2 1638360000000000000" + - label: cURL - Write with millisecond precision + lang: Shell + source: | + curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors&precision=ms" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01 usage=85.2 1638360000000" + - label: cURL - Asynchronous write with partial acceptance + lang: Shell + source: > + curl --request POST + "http://localhost:8181/api/v3/write_lp?db=sensors&accept_partial=true&no_sync=true&precision=auto" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01 usage=85.2 + memory,host=server01 used=4096" + - label: cURL - Multiple measurements with tags + lang: Shell + source: | + curl --request POST "http://localhost:8181/api/v3/write_lp?db=sensors&precision=ns" \ + --header "Authorization: Bearer DATABASE_TOKEN" \ + --header "Content-Type: text/plain" \ + --data-raw "cpu,host=server01,region=us-west usage=85.2,load=0.75 1638360000000000000 + memory,host=server01,region=us-west used=4096,free=12288 1638360000000000000 + disk,host=server01,region=us-west,device=/dev/sda1 used=50.5,free=49.5 1638360000000000000" + /health: + get: + operationId: GetHealth + responses: + "200": + description: Service is running. Returns `OK`. + content: + text/plain: + schema: + type: string + example: OK + "401": + description: Unauthorized. Authentication is required. + "500": + description: Service is unavailable. + summary: Health check + description: | + Checks the status of the service. + + Returns `OK` if the service is running. This endpoint does not return version information. + Use the [`/ping`](#operation/GetPing) endpoint to retrieve version details. + + > **Note**: This endpoint requires authentication by default in InfluxDB 3 Enterprise. + tags: + - Server information + /metrics: + get: + operationId: GetMetrics + responses: + "200": + description: Success + summary: Metrics + description: Retrieves Prometheus-compatible server metrics. + tags: + - Server information + /ping: + get: + operationId: GetPing + responses: + "200": + description: Success. The response body contains server information. + headers: + x-influxdb-version: + description: The InfluxDB version number (for example, `3.8.0`). + schema: + type: string + example: 3.8.0 + x-influxdb-build: + description: The InfluxDB build type (`Core` or `Enterprise`). + schema: + type: string + example: Enterprise + content: + application/json: + schema: + type: object + properties: + version: + type: string + description: The InfluxDB version number. + example: 3.8.0 + revision: + type: string + description: The git revision hash for the build. + example: 83b589b883 + process_id: + type: string + description: A unique identifier for the server process. + example: b756d9e0-cecd-4f72-b6d0-19e2d4f8cbb7 + "401": + description: Unauthorized. Authentication is required. + "404": + description: | + Not Found. Returned for HEAD requests. + Use a GET request to retrieve version information. + x-client-method: ping + summary: Ping the server + description: | + Returns version information for the server. + + **Important**: Use a GET request. HEAD requests return `404 Not Found`. + + The response includes version information in both headers and the JSON body: + + - **Headers**: `x-influxdb-version` and `x-influxdb-build` + - **Body**: JSON object with `version`, `revision`, and `process_id` + + > **Note**: This endpoint requires authentication by default in InfluxDB 3 Enterprise. + tags: + - Server information + post: + operationId: ping + responses: + "200": + description: Success. The response body contains server information. + headers: + x-influxdb-version: + description: The InfluxDB version number (for example, `3.8.0`). + schema: + type: string + example: 3.8.0 + x-influxdb-build: + description: The InfluxDB build type (`Core` or `Enterprise`). + schema: + type: string + example: Enterprise + content: + application/json: + schema: + type: object + properties: + version: + type: string + description: The InfluxDB version number. + example: 3.8.0 + revision: + type: string + description: The git revision hash for the build. + example: 83b589b883 + process_id: + type: string + description: A unique identifier for the server process. + example: b756d9e0-cecd-4f72-b6d0-19e2d4f8cbb7 + "401": + description: Unauthorized. Authentication is required. + "404": + description: | + Not Found. Returned for HEAD requests. + Use a GET request to retrieve version information. + summary: Ping the server + description: Returns version information for the server. Accepts POST in addition to GET. + tags: + - Server information + /query: + get: + operationId: GetV1ExecuteQuery + responses: + "200": + description: | + Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + application/csv: + schema: + type: string + headers: + Content-Type: + description: > + The content type of the response. + + Default is `application/json`. + + + If the `Accept` request header is `application/csv` or `text/csv`, the `Content-type` response header is + `application/csv` + + and the response is formatted as CSV. + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query (v1-compatible) + description: > + Executes an InfluxQL query to retrieve data from the specified database. + + + This endpoint is compatible with InfluxDB 1.x client libraries and third-party integrations such as Grafana. + + Use query parameters to specify the database and the InfluxQL query. + + + #### Related + + + - [Use the InfluxDB v1 HTTP query API and InfluxQL to query + data](/influxdb3/enterprise/query-data/execute-queries/influxdb-v1-api/) + parameters: + - name: Accept + in: header + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + - text/csv + required: false + description: > + The content type that the client can understand. + + + If `text/csv` is specified, the `Content-type` response header is `application/csv` and the response is + formatted as CSV. + + + Returns an error if the format is invalid or non-UTF8. + - in: query + name: chunked + description: | + If true, the response is divided into chunks of size `chunk_size`. + schema: + type: boolean + default: false + - in: query + name: chunk_size + description: | + The number of records that will go into a chunk. + This parameter is only used if `chunked=true`. + schema: + type: integer + default: 10000 + - in: query + name: db + description: The database to query. If not provided, the InfluxQL query string must specify the database. + schema: + type: string + format: InfluxQL + - in: query + name: pretty + description: | + If true, the JSON response is formatted in a human-readable format. + schema: + type: boolean + default: false + - in: query + name: q + description: The InfluxQL query string. + required: true + schema: + type: string + - name: epoch + description: > + Formats timestamps as [unix (epoch) timestamps](/influxdb3/enterprise/reference/glossary/#unix-timestamp) + with the specified precision + + instead of [RFC3339 timestamps](/influxdb3/enterprise/reference/glossary/#rfc3339-timestamp) with nanosecond + precision. + in: query + schema: + $ref: "#/components/schemas/EpochCompatibility" + - $ref: "#/components/parameters/v1UsernameParam" + - $ref: "#/components/parameters/v1PasswordParam" + - name: rp + in: query + required: false + schema: + type: string + description: | + Retention policy name. Honored but discouraged. InfluxDB 3 doesn't use retention policies. + - name: Authorization + in: header + required: false + schema: + type: string + description: | + Authorization header for token-based authentication. + Supported schemes: + - `Bearer AUTH_TOKEN` - OAuth bearer token scheme + - `Token AUTH_TOKEN` - InfluxDB v2 token scheme + - `Basic ` - Basic authentication (username is ignored) + tags: + - Query data + - Compatibility endpoints + post: + operationId: PostExecuteV1Query + responses: + "200": + description: | + Success. The response body contains query results. + content: + application/json: + schema: + $ref: "#/components/schemas/QueryResponse" + application/csv: + schema: + type: string + headers: + Content-Type: + description: > + The content type of the response. + + Default is `application/json`. + + + If the `Accept` request header is `application/csv` or `text/csv`, the `Content-type` response header is + `application/csv` + + and the response is formatted as CSV. + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + "400": + description: Bad request. + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "404": + description: Database not found. + "405": + description: Method not allowed. + "422": + description: Unprocessable entity. + summary: Execute InfluxQL query (v1-compatible) + description: > + Executes an InfluxQL query to retrieve data from the specified database. + + + #### Related + + + - [Use the InfluxDB v1 HTTP query API and InfluxQL to query + data](/influxdb3/enterprise/query-data/execute-queries/influxdb-v1-api/) + parameters: + - name: Accept + in: header + schema: + type: string + default: application/json + enum: + - application/json + - application/csv + - text/csv + required: false + description: > + The content type that the client can understand. + + + If `text/csv` is specified, the `Content-type` response header is `application/csv` and the response is + formatted as CSV. + + + Returns an error if the format is invalid or non-UTF8. + requestBody: + content: + application/json: + schema: + type: object + properties: + db: + type: string + description: The database to query. If not provided, the InfluxQL query string must specify the database. + q: + description: The InfluxQL query string. + type: string + chunked: + description: | + If true, the response is divided into chunks of size `chunk_size`. + type: boolean + chunk_size: + description: | + The number of records that will go into a chunk. + This parameter is only used if `chunked=true`. + type: integer + default: 10000 + epoch: + description: > + A unix timestamp precision. + + + - `h` for hours + + - `m` for minutes + + - `s` for seconds + + - `ms` for milliseconds + + - `u` or `µ` for microseconds + + - `ns` for nanoseconds + + + Formats timestamps as [unix (epoch) + timestamps](/influxdb3/enterprise/reference/glossary/#unix-timestamp) with the specified precision + + instead of [RFC3339 timestamps](/influxdb3/enterprise/reference/glossary/#rfc3339-timestamp) with + nanosecond precision. + enum: + - ns + - u + - µ + - ms + - s + - m + - h + type: string + pretty: + description: | + If true, the JSON response is formatted in a human-readable format. + type: boolean + required: + - q + application/x-www-form-urlencoded: + schema: + type: object + properties: + db: + type: string + description: The database to query. If not provided, the InfluxQL query string must specify the database. + q: + description: The InfluxQL query string. + type: string + chunked: + description: | + If true, the response is divided into chunks of size `chunk_size`. + type: boolean + chunk_size: + description: | + The number of records that will go into a chunk. + This parameter is only used if `chunked=true`. + type: integer + default: 10000 + epoch: + description: > + A unix timestamp precision. + + + - `h` for hours + + - `m` for minutes + + - `s` for seconds + + - `ms` for milliseconds + + - `u` or `µ` for microseconds + + - `ns` for nanoseconds + + + Formats timestamps as [unix (epoch) + timestamps](/influxdb3/enterprise/reference/glossary/#unix-timestamp) with the specified precision + + instead of [RFC3339 timestamps](/influxdb3/enterprise/reference/glossary/#rfc3339-timestamp) with + nanosecond precision. + enum: + - ns + - u + - µ + - ms + - s + - m + - h + type: string + pretty: + description: | + If true, the JSON response is formatted in a human-readable format. + type: boolean + required: + - q + application/vnd.influxql: + schema: + type: string + description: InfluxQL query string sent as the request body. + tags: + - Query data + - Compatibility endpoints + /write: + post: + operationId: PostV1Write + responses: + "204": + description: Success ("No Content"). All data in the batch is written and queryable. + headers: + cluster-uuid: + $ref: "#/components/headers/ClusterUUID" + "400": + description: | + Bad request. Some (a _partial write_) or all of the data from the batch was rejected and not written. + If a partial write occurred, then some points from the batch are written and queryable. + + The response body: + - indicates if a partial write occurred or all data was rejected. + - contains details about the [rejected points](/influxdb3/enterprise/write-data/troubleshoot/#troubleshoot-rejected-points), up to 100 points. + content: + application/json: + examples: + rejectedAllPoints: + summary: Rejected all points in the batch + value: | + { + "error": "write of line protocol failed", + "data": [ + { + "original_line": "dquote> home,room=Kitchen temp=hi", + "line_number": 2, + "error_message": "No fields were provided" + } + ] + } + partialWriteErrorWithRejectedPoints: + summary: Partial write rejected some points in the batch + value: | + { + "error": "partial write of line protocol occurred", + "data": [ + { + "original_line": "dquote> home,room=Kitchen temp=hi", + "line_number": 2, + "error_message": "No fields were provided" + } + ] + } + "401": + $ref: "#/components/responses/Unauthorized" + "403": + description: Access denied. + "413": + description: Request entity too large. + summary: Write line protocol (v1-compatible) + description: > + Writes line protocol to the specified database. + + + This endpoint provides backward compatibility for InfluxDB 1.x write workloads using tools such as InfluxDB 1.x + client libraries, the Telegraf `outputs.influxdb` output plugin, or third-party tools. + + + Use this endpoint to send data in [line + protocol](https://docs.influxdata.com/influxdb3/enterprise/reference/syntax/line-protocol/) format to InfluxDB. + + Use query parameters to specify options for writing data. + + + #### Related + + + - [Use compatibility APIs to write data](/influxdb3/enterprise/write-data/http-api/compatibility-apis/) + parameters: + - $ref: "#/components/parameters/dbWriteParam" + - $ref: "#/components/parameters/compatibilityPrecisionParam" + - $ref: "#/components/parameters/v1UsernameParam" + - $ref: "#/components/parameters/v1PasswordParam" + - name: rp + in: query + required: false + schema: + type: string + description: | + Retention policy name. Honored but discouraged. InfluxDB 3 doesn't use retention policies. + - name: consistency + in: query + required: false + schema: + type: string + description: | + Write consistency level. Ignored by InfluxDB 3. Provided for compatibility with InfluxDB 1.x clients. + - name: Authorization + in: header + required: false + schema: + type: string + description: | + Authorization header for token-based authentication. + Supported schemes: + - `Bearer AUTH_TOKEN` - OAuth bearer token scheme + - `Token AUTH_TOKEN` - InfluxDB v2 token scheme + - `Basic ` - Basic authentication (username is ignored) + - name: Content-Type + in: header + description: | + The content type of the request payload. + schema: + $ref: "#/components/schemas/LineProtocol" + required: false + - name: Accept + in: header + description: | + The content type that the client can understand. + Writes only return a response body if they fail (partially or completely)--for example, + due to a syntax problem or type mismatch. + schema: + type: string + default: application/json + enum: + - application/json + required: false + - $ref: "#/components/parameters/ContentEncoding" + - $ref: "#/components/parameters/ContentLength" + requestBody: + $ref: "#/components/requestBodies/lineProtocolRequestBody" + tags: + - Compatibility endpoints + - Write data +components: + parameters: + AcceptQueryHeader: + name: Accept + in: header + schema: + type: string + default: application/json + enum: + - application/json + - application/jsonl + - application/vnd.apache.parquet + - text/csv + required: false + description: | + The content type that the client can understand. + ContentEncoding: + name: Content-Encoding + in: header + description: | + The compression applied to the line protocol in the request payload. + To send a gzip payload, pass `Content-Encoding: gzip` header. + schema: + $ref: "#/components/schemas/ContentEncoding" + required: false + ContentLength: + name: Content-Length + in: header + description: | + The size of the entity-body, in bytes, sent to InfluxDB. + schema: + $ref: "#/components/schemas/ContentLength" + ContentType: + name: Content-Type + description: | + The format of the data in the request body. + in: header + schema: + type: string + enum: + - application/json + required: false + db: + name: db + in: query + required: true + schema: + type: string + description: | + The name of the database. + dbWriteParam: + name: db + in: query + required: true + schema: + type: string + description: | + The name of the database. + InfluxDB creates the database if it doesn't already exist, and then + writes all points in the batch to the database. + dbQueryParam: + name: db + in: query + required: false + schema: + type: string + description: | + The name of the database. + + If you provide a query that specifies the database, you can omit the 'db' parameter from your request. + accept_partial: + name: accept_partial + in: query + required: false + schema: + $ref: "#/components/schemas/AcceptPartial" + compatibilityPrecisionParam: + name: precision + in: query + required: false + schema: + $ref: "#/components/schemas/PrecisionWriteCompatibility" + description: The precision for unix timestamps in the line protocol batch. + precisionParam: + name: precision + in: query + required: false + schema: + $ref: "#/components/schemas/PrecisionWrite" + description: The precision for unix timestamps in the line protocol batch. + querySqlParam: + name: q + in: query + required: true + schema: + type: string + format: SQL + description: | + The query to execute. + format: + name: format + in: query + required: false + schema: + $ref: "#/components/schemas/Format" + formatRequired: + name: format + in: query + required: true + schema: + $ref: "#/components/schemas/Format" + v1UsernameParam: + name: u + in: query + required: false + schema: + type: string + description: > + Username for v1 compatibility authentication. + + When using Basic authentication or query string authentication, InfluxDB 3 ignores this parameter but allows any + arbitrary string for compatibility with InfluxDB 1.x clients. + v1PasswordParam: + name: p + in: query + required: false + schema: + type: string + description: | + Password for v1 compatibility authentication. + For query string authentication, pass a database token with write permissions as this parameter. + InfluxDB 3 checks that the `p` value is an authorized token. + requestBodies: + lineProtocolRequestBody: + required: true + content: + text/plain: + schema: + type: string + examples: + line: + summary: Example line protocol + value: measurement,tag=value field=1 1234567890 + multiline: + summary: Example line protocol with UTF-8 characters + value: | + measurement,tag=value field=1 1234567890 + measurement,tag=value field=2 1234567900 + measurement,tag=value field=3 1234568000 + queryRequestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/QueryRequestObject" + schemas: + AdminTokenObject: + type: object + properties: + id: + type: integer + name: + type: string + token: + type: string + hash: + type: string + created_at: + type: string + format: date-time + expiry: + format: date-time + example: + id: 0 + name: _admin + token: apiv3_00xx0Xx0xx00XX0x0 + hash: 00xx0Xx0xx00XX0x0 + created_at: "2025-04-18T14:02:45.331Z" + expiry: null + ResourceTokenObject: + type: object + properties: + token_name: + type: string + permissions: + type: array + items: + type: object + properties: + resource_type: + type: string + enum: + - system + - db + actions: + type: array + items: + type: string + enum: + - read + - write + resource_names: + type: array + items: + type: string + description: List of resource names. Use "*" for all resources. + expiry_secs: + type: integer + description: The expiration time in seconds. + example: + token_name: All system information + permissions: + - resource_type: system + actions: + - read + resource_names: + - "*" + expiry_secs: 300000 + ContentEncoding: + type: string + enum: + - gzip + - identity + description: > + Content coding. + + Use `gzip` for compressed data or `identity` for unmodified, uncompressed data. + + + #### Multi-member gzip support + + + InfluxDB 3 supports multi-member gzip payloads (concatenated gzip files per [RFC + 1952](https://www.rfc-editor.org/rfc/rfc1952)). + + This allows you to: + + - Concatenate multiple gzip files and send them in a single request + + - Maintain compatibility with InfluxDB v1 and v2 write endpoints + + - Simplify batch operations using standard compression tools + default: identity + LineProtocol: + type: string + enum: + - text/plain + - text/plain; charset=utf-8 + description: | + `text/plain` is the content type for line protocol. `UTF-8` is the default character set. + default: text/plain; charset=utf-8 + ContentLength: + type: integer + description: The length in decimal number of octets. + Database: + type: string + AcceptPartial: + type: boolean + default: true + description: Accept partial writes. + Format: + type: string + enum: + - json + - csv + - parquet + - json_lines + - jsonl + - pretty + description: |- + The format of data in the response body. + `json_lines` is the canonical name; `jsonl` is accepted as an alias. + NoSync: + type: boolean + default: false + description: | + Acknowledges a successful write without waiting for WAL persistence. + + #### Related + + - [Use the HTTP API and client libraries to write data](/influxdb3/enterprise/write-data/api-client-libraries/) + - [Data durability](/influxdb3/enterprise/reference/internals/durability/) + PrecisionWriteCompatibility: + enum: + - ms + - s + - us + - u + - ns + - "n" + type: string + description: |- + The precision for unix timestamps in the line protocol batch. + Use `ms` for milliseconds, `s` for seconds, `us` or `u` for microseconds, or `ns` or `n` for nanoseconds. + Optional — defaults to nanosecond precision if omitted. + PrecisionWrite: + enum: + - auto + - nanosecond + - microsecond + - millisecond + - second + type: string + description: | + The precision for unix timestamps in the line protocol batch. + + Supported values: + - `auto` (default): Automatically detects precision based on timestamp magnitude + - `nanosecond`: Nanoseconds + - `microsecond`: Microseconds + - `millisecond`: Milliseconds + - `second`: Seconds + QueryRequestObject: + type: object + properties: + db: + description: | + The name of the database to query. + Required if the query (`q`) doesn't specify the database. + type: string + q: + description: The query to execute. + type: string + format: + description: The format of the query results. + type: string + enum: + - json + - csv + - parquet + - json_lines + - jsonl + - pretty + params: + description: | + Additional parameters for the query. + Use this field to pass query parameters. + type: object + additionalProperties: true + required: + - db + - q + example: + db: mydb + q: SELECT * FROM mytable + format: json + params: {} + CreateDatabaseRequest: + type: object + properties: + db: + type: string + pattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$ + description: |- + The database name. Database names cannot contain underscores (_). + Names must start and end with alphanumeric characters and can contain hyphens (-) in the middle. + retention_period: + type: string + description: |- + The retention period for the database. Specifies how long data should be retained. + Use duration format (for example, "1d", "1h", "30m", "7d"). + example: 7d + required: + - db + CreateTableRequest: + type: object + properties: + db: + type: string + table: + type: string + tags: + type: array + items: + type: string + fields: + type: array + items: + type: object + properties: + name: + type: string + type: + type: string + enum: + - utf8 + - int64 + - uint64 + - float64 + - bool + required: + - name + - type + retention_period: + type: string + description: |- + The retention period for the table. Specifies how long data in this table should be retained. + Use duration format (for example, "1d", "1h", "30m", "7d"). + example: 30d + required: + - db + - table + - tags + - fields + DistinctCacheCreateRequest: + type: object + properties: + db: + type: string + table: + type: string + node_spec: + $ref: "#/components/schemas/ApiNodeSpec" + name: + type: string + description: Optional cache name. + columns: + type: array + items: + type: string + max_cardinality: + type: integer + description: Optional maximum cardinality. + max_age: + type: integer + description: Optional maximum age in seconds. + required: + - db + - table + - columns + example: + db: mydb + table: mytable + columns: + - tag1 + - tag2 + max_cardinality: 1000 + max_age: 3600 + LastCacheCreateRequest: + type: object + properties: + db: + type: string + table: + type: string + node_spec: + $ref: "#/components/schemas/ApiNodeSpec" + name: + type: string + description: Optional cache name. + key_columns: + type: array + items: + type: string + description: Optional list of key columns. + value_columns: + type: array + items: + type: string + description: Optional list of value columns. + count: + type: integer + description: Optional count. + ttl: + type: integer + description: Optional time-to-live in seconds. + required: + - db + - table + example: + db: mydb + table: mytable + key_columns: + - tag1 + value_columns: + - field1 + count: 100 + ttl: 3600 + ProcessingEngineTriggerRequest: + type: object + properties: + db: + type: string + plugin_filename: + type: string + description: | + The path and filename of the plugin to execute--for example, + `schedule.py` or `endpoints/report.py`. + The path can be absolute or relative to the `--plugins-dir` directory configured when starting InfluxDB 3. + + The plugin file must implement the trigger interface associated with the trigger's specification. + node_spec: + $ref: "#/components/schemas/ApiNodeSpec" + trigger_name: + type: string + trigger_settings: + description: | + Configuration for trigger error handling and execution behavior. + allOf: + - $ref: "#/components/schemas/TriggerSettings" + trigger_specification: + description: > + Specifies when and how the processing engine trigger should be invoked. + + + ## Supported trigger specifications: + + + ### Cron-based scheduling + + Format: `cron:CRON_EXPRESSION` + + + Uses extended (6-field) cron format (second minute hour day_of_month month day_of_week): + + ``` + + ┌───────────── second (0-59) + + │ ┌───────────── minute (0-59) + + │ │ ┌───────────── hour (0-23) + + │ │ │ ┌───────────── day of month (1-31) + + │ │ │ │ ┌───────────── month (1-12) + + │ │ │ │ │ ┌───────────── day of week (0-6, Sunday=0) + + │ │ │ │ │ │ + + * * * * * * + + ``` + + Examples: + + - `cron:0 0 6 * * 1-5` - Every weekday at 6:00 AM + + - `cron:0 30 14 * * 5` - Every Friday at 2:30 PM + + - `cron:0 0 0 1 * *` - First day of every month at midnight + + + ### Interval-based scheduling + + Format: `every:DURATION` + + + Supported durations: `s` (seconds), `m` (minutes), `h` (hours), `d` (days), `w` (weeks), `M` (months), `y` + (years): + + - `every:30s` - Every 30 seconds + + - `every:5m` - Every 5 minutes + + - `every:1h` - Every hour + + - `every:1d` - Every day + + - `every:1w` - Every week + + - `every:1M` - Every month + + - `every:1y` - Every year + + + **Maximum interval**: 1 year + + + ### Table-based triggers + + - `all_tables` - Triggers on write events to any table in the database + + - `table:TABLE_NAME` - Triggers on write events to a specific table + + + ### On-demand triggers + + Format: `request:REQUEST_PATH` + + + Creates an HTTP endpoint `/api/v3/engine/REQUEST_PATH` for manual invocation: + + - `request:hello-world` - Creates endpoint `/api/v3/engine/hello-world` + + - `request:data-export` - Creates endpoint `/api/v3/engine/data-export` + pattern: ^(cron:[0-9 *,/-]+|every:[0-9]+[smhd]|all_tables|table:[a-zA-Z_][a-zA-Z0-9_]*|request:[a-zA-Z0-9_-]+)$ + example: cron:0 0 6 * * 1-5 + trigger_arguments: + type: object + additionalProperties: true + description: Optional arguments passed to the plugin. + disabled: + type: boolean + default: false + description: Whether the trigger is disabled. + required: + - db + - plugin_filename + - trigger_name + - trigger_settings + - trigger_specification + - disabled + TriggerSettings: + type: object + description: | + Configuration settings for processing engine trigger error handling and execution behavior. + properties: + run_async: + type: boolean + default: false + description: | + Whether to run the trigger asynchronously. + When `true`, the trigger executes in the background without blocking. + When `false`, the trigger executes synchronously. + error_behavior: + type: string + enum: + - Log + - Retry + - Disable + description: | + Specifies how to handle errors that occur during trigger execution: + - `Log`: Log the error and continue (default) + - `Retry`: Retry the trigger execution + - `Disable`: Disable the trigger after an error + default: Log + required: + - run_async + - error_behavior + ApiNodeSpec: + x-enterprise-only: true + type: object + description: | + Optional specification for targeting specific nodes in a multi-node InfluxDB 3 Enterprise cluster. + Use this to control which node(s) should handle the cache or trigger. + properties: + node_id: + type: string + description: | + The ID of a specific node in the cluster. + If specified, the cache or trigger will only be created on this node. + node_group: + type: string + description: | + The name of a node group in the cluster. + If specified, the cache or trigger will be created on all nodes in this group. + WALPluginTestRequest: + type: object + description: | + Request body for testing a write-ahead logging (WAL) plugin. + properties: + filename: + type: string + description: | + The path and filename of the plugin to test. + database: + type: string + description: | + The database name to use for the test. + input_lp: + type: string + description: | + Line protocol data to use as input for the test. + cache_name: + type: string + description: | + Optional name of the cache to use in the test. + input_arguments: + type: object + additionalProperties: + type: string + description: | + Optional key-value pairs of arguments to pass to the plugin. + required: + - filename + - database + - input_lp + SchedulePluginTestRequest: + type: object + description: | + Request body for testing a scheduling plugin. + properties: + filename: + type: string + description: | + The path and filename of the plugin to test. + database: + type: string + description: | + The database name to use for the test. + schedule: + type: string + description: | + Optional schedule specification in cron or interval format. + cache_name: + type: string + description: | + Optional name of the cache to use in the test. + input_arguments: + type: object + additionalProperties: + type: string + description: | + Optional key-value pairs of arguments to pass to the plugin. + required: + - filename + - database + PluginFileRequest: + type: object + description: | + Request body for updating a plugin file. + properties: + plugin_name: + type: string + description: | + The name of the plugin file to update. + content: + type: string + description: | + The content of the plugin file. + required: + - plugin_name + - content + PluginDirectoryRequest: + type: object + description: | + Request body for updating plugin directory with multiple files. + properties: + plugin_name: + type: string + description: | + The name of the plugin directory to update. + files: + type: array + items: + $ref: "#/components/schemas/PluginFileEntry" + description: | + List of plugin files to include in the directory. + required: + - plugin_name + - files + PluginFileEntry: + type: object + description: | + Represents a single file in a plugin directory. + properties: + content: + type: string + description: | + The content of the file. + relative_path: + type: string + description: The relative path of the file within the plugin directory. + required: + - relative_path + - content + ShowDatabasesResponse: + type: object + properties: + databases: + type: array + items: + type: string + QueryResponse: + type: object + properties: + results: + type: array + items: + type: object + example: + results: + - series: + - name: mytable + columns: + - time + - value + values: + - - "2024-02-02T12:00:00Z" + - 42 + ErrorMessage: + type: object + properties: + error: + type: string + data: + type: object + nullable: true + LineProtocolError: + properties: + code: + description: Code is the machine-readable error code. + enum: + - internal error + - not found + - conflict + - invalid + - empty value + - unavailable + readOnly: true + type: string + err: + description: Stack of errors that occurred during processing of the request. Useful for debugging. + readOnly: true + type: string + line: + description: First line in the request body that contains malformed data. + format: int32 + readOnly: true + type: integer + message: + description: Human-readable message. + readOnly: true + type: string + op: + description: Describes the logical code operation when the error occurred. Useful for debugging. + readOnly: true + type: string + required: + - code + EpochCompatibility: + description: | + A unix timestamp precision. + - `h` for hours + - `m` for minutes + - `s` for seconds + - `ms` for milliseconds + - `u` or `µ` for microseconds + - `ns` for nanoseconds + enum: + - ns + - u + - µ + - ms + - s + - m + - h + type: string + UpdateDatabaseRequest: + type: object + properties: + retention_period: + type: string + description: | + The retention period for the database. Specifies how long data should be retained. + Use duration format (for example, "1d", "1h", "30m", "7d"). + example: 7d + description: Request schema for updating database configuration. + UpdateTableRequest: + type: object + properties: + db: + type: string + description: The name of the database containing the table. + table: + type: string + description: The name of the table to update. + retention_period: + type: string + description: | + The retention period for the table. Specifies how long data in this table should be retained. + Use duration format (for example, "1d", "1h", "30m", "7d"). + example: 30d + required: + - db + - table + description: Request schema for updating table configuration. + LicenseResponse: + type: object + properties: + license_type: + type: string + description: The type of license (for example, "enterprise", "trial"). + example: enterprise + expires_at: + type: string + format: date-time + description: The expiration date of the license in ISO 8601 format. + example: "2025-12-31T23:59:59Z" + features: + type: array + items: + type: string + description: List of features enabled by the license. + example: + - clustering + - processing_engine + - advanced_auth + status: + type: string + enum: + - active + - expired + - invalid + description: The current status of the license. + example: active + description: Response schema for license information. + CreateTokenWithPermissionsRequest: + type: object + properties: + token_name: + type: string + description: The name for the resource token. + permissions: + type: array + items: + $ref: "#/components/schemas/PermissionDetailsApi" + description: List of permissions to grant to the token. + expiry_secs: + type: integer + description: Optional expiration time in seconds. + nullable: true + required: + - token_name + - permissions + PermissionDetailsApi: + type: object + properties: + resource_type: + type: string + enum: + - system + - db + description: The type of resource. + resource_names: + type: array + items: + type: string + description: List of resource names. Use "*" for all resources. + actions: + type: array + items: + type: string + enum: + - read + - write + description: List of actions to grant. + required: + - resource_type + - resource_names + - actions + FileIndexCreateRequest: + type: object + description: Request body for creating a file index. + properties: + db: + type: string + description: The database name. + table: + type: string + description: The table name. If omitted, the file index applies to the database. + nullable: true + columns: + type: array + items: + type: string + description: The columns to use for the file index. + required: + - db + - columns + example: + db: mydb + table: mytable + columns: + - tag1 + - tag2 + FileIndexDeleteRequest: + type: object + description: Request body for deleting a file index. + properties: + db: + type: string + description: The database name. + table: + type: string + description: The table name. If omitted, deletes the database-level file index. + nullable: true + required: + - db + example: + db: mydb + table: mytable + StopNodeRequest: + type: object + description: Request body for marking a node as stopped in the catalog. + properties: + node_id: + type: string + description: The ID of the node to mark as stopped. + required: + - node_id + example: + node_id: node-1 + responses: + Unauthorized: + description: Unauthorized access. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorMessage" + BadRequest: + description: | + Request failed. Possible reasons: + + - Invalid database name + - Malformed request body + - Invalid timestamp precision + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorMessage" + Forbidden: + description: Access denied. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorMessage" + NotFound: + description: Resource not found. + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorMessage" + headers: + ClusterUUID: + description: | + The catalog UUID of the InfluxDB instance. + This header is included in all HTTP API responses and enables you to: + - Identify which cluster instance handled the request + - Monitor deployments across multiple InfluxDB instances + - Debug and troubleshoot distributed systems + schema: + type: string + format: uuid + example: 01234567-89ab-cdef-0123-456789abcdef + securitySchemes: + BasicAuthentication: + type: http + scheme: basic + description: >- + Use the `Authorization` header with the `Basic` scheme to authenticate v1 API requests. + + + Works with v1 compatibility [`/write`](#operation/PostV1Write) and [`/query`](#operation/GetV1Query) endpoints + in InfluxDB 3. + + + When authenticating requests, InfluxDB 3 checks that the `password` part of the decoded credential is an + authorized token + + and ignores the `username` part of the decoded credential. + + + ### Syntax + + + ```http + + Authorization: Basic + + ``` + + + ### Example + + + ```bash + + curl "http://localhost:8181/write?db=DATABASE_NAME&precision=s" \ + --user "":"AUTH_TOKEN" \ + --header "Content-type: text/plain; charset=utf-8" \ + --data-binary 'home,room=kitchen temp=72 1641024000' + ``` + + + Replace the following: + + + - **`DATABASE_NAME`**: your InfluxDB 3 Enterprise database + + - **`AUTH_TOKEN`**: an admin token or database token authorized for the database + QuerystringAuthentication: + type: apiKey + in: query + name: u=&p= + description: >- + Use InfluxDB 1.x API parameters to provide credentials through the query string for v1 API requests. + + + Querystring authentication works with v1-compatible [`/write`](#operation/PostV1Write) and + [`/query`](#operation/GetV1Query) endpoints. + + + When authenticating requests, InfluxDB 3 checks that the `p` (_password_) query parameter is an authorized token + + and ignores the `u` (_username_) query parameter. + + + ### Syntax + + + ```http + + https://localhost:8181/query/?[u=any]&p=AUTH_TOKEN + + https://localhost:8181/write/?[u=any]&p=AUTH_TOKEN + + ``` + + + ### Examples + + + ```bash + + curl "http://localhost:8181/write?db=DATABASE_NAME&precision=s&p=AUTH_TOKEN" \ + --header "Content-type: text/plain; charset=utf-8" \ + --data-binary 'home,room=kitchen temp=72 1641024000' + ``` + + + Replace the following: + + + - **`DATABASE_NAME`**: your InfluxDB 3 Enterprise database + + - **`AUTH_TOKEN`**: an admin token or database token authorized for the database + + + ```bash + + ####################################### + + # Use an InfluxDB 1.x compatible username and password + + # to query the InfluxDB v1 HTTP API + + ####################################### + + # Use authentication query parameters: + + # ?p=AUTH_TOKEN + + ####################################### + + + curl --get "http://localhost:8181/query" \ + --data-urlencode "p=AUTH_TOKEN" \ + --data-urlencode "db=DATABASE_NAME" \ + --data-urlencode "q=SELECT * FROM MEASUREMENT" + ``` + + + Replace the following: + + + - **`DATABASE_NAME`**: the database to query + + - **`AUTH_TOKEN`**: a database token with sufficient permissions to the database + BearerAuthentication: + type: http + scheme: bearer + bearerFormat: JWT + description: | + + Use the OAuth Bearer authentication + scheme to provide an authorization token to InfluxDB 3. + + Bearer authentication works with all endpoints. + + In your API requests, send an `Authorization` header. + For the header value, provide the word `Bearer` followed by a space and a database token. + + ### Syntax + + ```http + Authorization: Bearer AUTH_TOKEN + ``` + + ### Example + + ```bash + curl http://localhost:8181/api/v3/query_influxql \ + --header "Authorization: Bearer AUTH_TOKEN" + ``` + TokenAuthentication: + description: |- + Use InfluxDB v2 Token authentication to provide an authorization token to InfluxDB 3. + + The v2 Token scheme works with v1 and v2 compatibility endpoints in InfluxDB 3. + + In your API requests, send an `Authorization` header. + For the header value, provide the word `Token` followed by a space and a database token. + The word `Token` is case-sensitive. + + ### Syntax + + ```http + Authorization: Token AUTH_TOKEN + ``` + + ### Example + + ```sh + ######################################################## + # Use the Token authentication scheme with /api/v2/write + # to write data. + ######################################################## + + curl --request post "http://localhost:8181/api/v2/write?bucket=DATABASE_NAME&precision=s" \ + --header "Authorization: Token AUTH_TOKEN" \ + --data-binary 'home,room=kitchen temp=72 1463683075' + ``` + in: header + name: Authorization + type: apiKey +x-tagGroups: + - name: Using the InfluxDB HTTP API + tags: + - Quick start + - Authentication + - Cache data + - Common parameters + - Response codes + - Compatibility endpoints + - Database + - Processing engine + - Server information + - Table + - Token + - Query data + - Write data diff --git a/assets/js/code-controls.js b/assets/js/code-controls.js index 59ca50ec7..d8ce5a9f9 100644 --- a/assets/js/code-controls.js +++ b/assets/js/code-controls.js @@ -7,10 +7,11 @@ function initialize() { var appendHTML = `
- -
    -
  • Copy
  • -
  • Fill window
  • + +
`; @@ -27,12 +28,17 @@ function initialize() { // Click outside of the code-controls to close them $(document).click(function () { - $('.code-controls').removeClass('open'); + $('.code-controls.open').each(function () { + $(this).removeClass('open'); + $(this).find('.code-controls-toggle').attr('aria-expanded', 'false'); + }); }); // Click the code controls toggle to open code controls $('.code-controls-toggle').click(function () { - $(this).parent('.code-controls').toggleClass('open'); + var $controls = $(this).parent('.code-controls'); + var isOpen = $controls.toggleClass('open').hasClass('open'); + $(this).attr('aria-expanded', String(isOpen)); }); // Stop event propagation for clicks inside of the code-controls div @@ -235,6 +241,34 @@ function initialize() { return info; } + ////////////////////////////////// ASK AI //////////////////////////////////// + + // Build a query from the code block and open Kapa via the ask-ai-open contract + $('.ask-ai-code').click(function () { + var codeElement = $(this) + .closest('.code-controls') + .prevAll('pre:has(code)')[0]; + if (!codeElement) return; + + var code = codeElement.innerText.trim(); + // Use the data-ask-ai-query attribute if the template provided one, + // otherwise build a generic query from the code content + var query = + $(codeElement).attr('data-ask-ai-query') || + 'Explain this code:\n```\n' + code.substring(0, 500) + '\n```'; + + // Delegate to the global ask-ai-open handler by synthesizing a click. + // Use native .click() instead of jQuery .trigger() so the event + // reaches the native document.addEventListener in ask-ai-trigger.js. + // No href — prevents scroll-to-top when the native click fires. + var triggerEl = document.createElement('a'); + triggerEl.className = 'ask-ai-open'; + triggerEl.dataset.query = query; + document.body.appendChild(triggerEl); + triggerEl.click(); + triggerEl.remove(); + }); + /////////////////////////////// FULL WINDOW CODE /////////////////////////////// /* diff --git a/assets/js/services/local-storage.js b/assets/js/services/local-storage.js index 8efccde12..22b778733 100644 --- a/assets/js/services/local-storage.js +++ b/assets/js/services/local-storage.js @@ -117,7 +117,10 @@ function getInfluxDBUrls() { initializeStorageItem('urls', JSON.stringify(DEFAULT_STORAGE_URLS)); } - return JSON.parse(localStorage.getItem(urlStorageKey)); + const storedUrls = JSON.parse(localStorage.getItem(urlStorageKey)); + // Backfill any new default keys missing from stored data (e.g., when new + // products like core/enterprise are added after a user's first visit). + return { ...DEFAULT_STORAGE_URLS, ...storedUrls }; } // Get the current or previous URL for a specific product or a custom url @@ -131,8 +134,8 @@ function getInfluxDBUrl(product) { const urlsString = localStorage.getItem(urlStorageKey); const urlsObj = JSON.parse(urlsString); - // Return the URL of the specified product - return urlsObj[product]; + // Return the URL of the specified product, falling back to the default + return urlsObj[product] ?? DEFAULT_STORAGE_URLS[product]; } /* diff --git a/assets/styles/layouts/_code-controls.scss b/assets/styles/layouts/_code-controls.scss index 36272a257..68353bed5 100644 --- a/assets/styles/layouts/_code-controls.scss +++ b/assets/styles/layouts/_code-controls.scss @@ -16,10 +16,12 @@ opacity: .5; transition: opacity .2s; border-radius: $radius; + border: none; + background: none; line-height: 0; - cursor: pointer; + cursor: pointer; - &:hover { + &:hover, &:focus-visible { opacity: 1; background-color: rgba($article-text, .1); backdrop-filter: blur(15px); @@ -35,21 +37,26 @@ backdrop-filter: blur(15px); display: none; - li { + button { + display: block; + width: 100%; + text-align: left; margin: 0; padding: .4rem .5rem .6rem; + border: none; + background: none; border-radius: $radius; color: $article-bold; font-size: .87rem; line-height: 0; - cursor: pointer; + cursor: pointer; - &:hover {background-color: rgba($article-text, .07)} - - &.copy-code, &.fullscreen-toggle { - .cf-icon {margin-right: .35rem;} + &:hover, &:focus-visible { + background-color: rgba($article-text, .07); } + .cf-icon {margin-right: .35rem;} + &.copy-code { .message { text-shadow: 0px 0px 8px rgba($article-text, 0); @@ -69,6 +76,8 @@ } } } + + li {margin: 0;} } &.open { diff --git a/content/enterprise_influxdb/v1/administration/manage/clusters/rebalance.md b/content/enterprise_influxdb/v1/administration/manage/clusters/rebalance.md index 020133649..75bc3778c 100644 --- a/content/enterprise_influxdb/v1/administration/manage/clusters/rebalance.md +++ b/content/enterprise_influxdb/v1/administration/manage/clusters/rebalance.md @@ -289,8 +289,8 @@ Run the query on any data node for each retention policy and database. Here, we use InfluxDB's [CLI](/enterprise_influxdb/v1/tools/influx-cli/use-influx/) to execute the query: ``` -> ALTER RETENTION POLICY "" ON "" REPLICATION 3 -> +ALTER RETENTION POLICY "" ON "" REPLICATION 3 + ``` A successful `ALTER RETENTION POLICY` query returns no results. diff --git a/content/enterprise_influxdb/v1/administration/manage/users-and-permissions/authorization-influxql.md b/content/enterprise_influxdb/v1/administration/manage/users-and-permissions/authorization-influxql.md index f9bcf1bf6..a132289b7 100644 --- a/content/enterprise_influxdb/v1/administration/manage/users-and-permissions/authorization-influxql.md +++ b/content/enterprise_influxdb/v1/administration/manage/users-and-permissions/authorization-influxql.md @@ -124,11 +124,11 @@ CREATE USER WITH PASSWORD '' ###### CLI example ```js -> CREATE USER todd WITH PASSWORD 'influxdb41yf3' -> CREATE USER alice WITH PASSWORD 'wonder\'land' -> CREATE USER "rachel_smith" WITH PASSWORD 'asdf1234!' -> CREATE USER "monitoring-robot" WITH PASSWORD 'XXXXX' -> CREATE USER "$savyadmin" WITH PASSWORD 'm3tr1cL0v3r' +CREATE USER todd WITH PASSWORD 'influxdb41yf3' +CREATE USER alice WITH PASSWORD 'wonder\'land' +CREATE USER "rachel_smith" WITH PASSWORD 'asdf1234!' +CREATE USER "monitoring-robot" WITH PASSWORD 'XXXXX' +CREATE USER "$savyadmin" WITH PASSWORD 'm3tr1cL0v3r' ``` {{% note %}} @@ -169,13 +169,13 @@ CLI examples: `GRANT` `READ` access to `todd` on the `NOAA_water_database` database: ```sql -> GRANT READ ON "NOAA_water_database" TO "todd" +GRANT READ ON "NOAA_water_database" TO "todd" ``` `GRANT` `ALL` access to `todd` on the `NOAA_water_database` database: ```sql -> GRANT ALL ON "NOAA_water_database" TO "todd" +GRANT ALL ON "NOAA_water_database" TO "todd" ``` ##### `REVOKE` `READ`, `WRITE`, or `ALL` database privileges from an existing user @@ -189,13 +189,13 @@ CLI examples: `REVOKE` `ALL` privileges from `todd` on the `NOAA_water_database` database: ```sql -> REVOKE ALL ON "NOAA_water_database" FROM "todd" +REVOKE ALL ON "NOAA_water_database" FROM "todd" ``` `REVOKE` `WRITE` privileges from `todd` on the `NOAA_water_database` database: ```sql -> REVOKE WRITE ON "NOAA_water_database" FROM "todd" +REVOKE WRITE ON "NOAA_water_database" FROM "todd" ``` {{% note %}} @@ -230,7 +230,7 @@ SET PASSWORD FOR = '' CLI example: ```sql -> SET PASSWORD FOR "todd" = 'password4todd' +SET PASSWORD FOR "todd" = 'password4todd' ``` {{% note %}} @@ -250,6 +250,6 @@ DROP USER CLI example: ```sql -> DROP USER "todd" +DROP USER "todd" ``` diff --git a/content/enterprise_influxdb/v1/flux/get-started/syntax-basics.md b/content/enterprise_influxdb/v1/flux/get-started/syntax-basics.md index e48c0b79b..710cbb2bb 100644 --- a/content/enterprise_influxdb/v1/flux/get-started/syntax-basics.md +++ b/content/enterprise_influxdb/v1/flux/get-started/syntax-basics.md @@ -28,9 +28,9 @@ For example, simple addition: Assign an expression to a variable using the assignment operator, `=`. ```js -> s = "this is a string" -> i = 1 // an integer -> f = 2.0 // a floating point number +s = "this is a string" +i = 1 // an integer +f = 2.0 // a floating point number ``` Type the name of a variable to print its value: @@ -48,7 +48,7 @@ this is a string Flux also supports records. Each value in a record can be a different data type. ```js -> o = {name:"Jim", age: 42, "favorite color": "red"} +o = {name:"Jim", age: 42, "favorite color": "red"} ``` Use **dot notation** to access a properties of a record: diff --git a/content/enterprise_influxdb/v1/guides/downsample_and_retain.md b/content/enterprise_influxdb/v1/guides/downsample_and_retain.md index c544c276e..81c4238fd 100644 --- a/content/enterprise_influxdb/v1/guides/downsample_and_retain.md +++ b/content/enterprise_influxdb/v1/guides/downsample_and_retain.md @@ -70,7 +70,7 @@ the CQ has no `FOR` clause. #### 1. Create the database ```sql -> CREATE DATABASE "food_data" +CREATE DATABASE "food_data" ``` #### 2. Create a two-hour `DEFAULT` retention policy @@ -85,7 +85,7 @@ Use the statement to create a `DEFAULT` RP: ```sql -> CREATE RETENTION POLICY "two_hours" ON "food_data" DURATION 2h REPLICATION 1 DEFAULT +CREATE RETENTION POLICY "two_hours" ON "food_data" DURATION 2h REPLICATION 1 DEFAULT ``` That query creates an RP called `two_hours` that exists in the database @@ -116,7 +116,7 @@ Use the statement to create a non-`DEFAULT` retention policy: ```sql -> CREATE RETENTION POLICY "a_year" ON "food_data" DURATION 52w REPLICATION 1 +CREATE RETENTION POLICY "a_year" ON "food_data" DURATION 52w REPLICATION 1 ``` That query creates a retention policy (RP) called `a_year` that exists in the database diff --git a/content/enterprise_influxdb/v1/query_language/continuous_queries.md b/content/enterprise_influxdb/v1/query_language/continuous_queries.md index 1ca7d56b7..76cb98168 100644 --- a/content/enterprise_influxdb/v1/query_language/continuous_queries.md +++ b/content/enterprise_influxdb/v1/query_language/continuous_queries.md @@ -839,8 +839,7 @@ DROP CONTINUOUS QUERY ON Drop the `idle_hands` CQ from the `telegraf` database: ```sql -> DROP CONTINUOUS QUERY "idle_hands" ON "telegraf"` -> +DROP CONTINUOUS QUERY "idle_hands" ON "telegraf" ``` ### Altering continuous queries diff --git a/content/enterprise_influxdb/v1/query_language/explore-data.md b/content/enterprise_influxdb/v1/query_language/explore-data.md index a4b880ed7..1cf896f9b 100644 --- a/content/enterprise_influxdb/v1/query_language/explore-data.md +++ b/content/enterprise_influxdb/v1/query_language/explore-data.md @@ -380,8 +380,7 @@ The following query returns no data because it specifies a single tag key (`loca the `SELECT` clause: ```sql -> SELECT "location" FROM "h2o_feet" -> +SELECT "location" FROM "h2o_feet" ``` To return any data associated with the `location` tag key, the query's `SELECT` @@ -597,7 +596,7 @@ separating logic with parentheses. #### Select data that have specific timestamps ```sql -> SELECT * FROM "h2o_feet" WHERE time > now() - 7d +SELECT * FROM "h2o_feet" WHERE time > now() - 7d ``` The query returns data from the `h2o_feet` measurement that have [timestamps](/enterprise_influxdb/v1/concepts/glossary/#timestamp) @@ -1592,8 +1591,8 @@ the query's time range. Note that `fill(800)` has no effect on the query results. ```sql -> SELECT MEAN("water_level") FROM "h2o_feet" WHERE "location" = 'coyote_creek' AND time >= '2015-09-18T22:00:00Z' AND time <= '2015-09-18T22:18:00Z' GROUP BY time(12m) fill(800) -> +SELECT MEAN("water_level") FROM "h2o_feet" WHERE "location" = 'coyote_creek' AND time >= '2015-09-18T22:00:00Z' AND time <= '2015-09-18T22:18:00Z' GROUP BY time(12m) fill(800) + ``` ##### Queries with `fill(previous)` when the previous result falls outside the query's time range @@ -2639,7 +2638,7 @@ The whitespace between `-` or `+` and the [duration literal](/enterprise_influxd #### Specify a time range with relative time ```sql -> SELECT "water_level" FROM "h2o_feet" WHERE time > now() - 1h +SELECT "water_level" FROM "h2o_feet" WHERE time > now() - 1h ``` The query returns data with timestamps that occur within the past hour. @@ -2686,7 +2685,7 @@ a `GROUP BY time()` clause must provide an alternative upper bound in the Use the [CLI](/enterprise_influxdb/v1/tools/influx-cli/use-influx/) to write a point to the `NOAA_water_database` that occurs after `now()`: ```sql -> INSERT h2o_feet,location=santa_monica water_level=3.1 1587074400000000000 +INSERT h2o_feet,location=santa_monica water_level=3.1 1587074400000000000 ``` Run a `GROUP BY time()` query that covers data with timestamps between @@ -2722,8 +2721,8 @@ the lower bound to `now()` such that the query's time range is between `now()` and `now()`: ```sql -> SELECT MEAN("water_level") FROM "h2o_feet" WHERE "location"='santa_monica' AND time >= now() GROUP BY time(12m) fill(none) -> +SELECT MEAN("water_level") FROM "h2o_feet" WHERE "location"='santa_monica' AND time >= now() GROUP BY time(12m) fill(none) + ``` ### Configuring the returned timestamps @@ -2831,8 +2830,8 @@ includes an `m` and `water_level` is greater than three. #### Use a regular expression to specify a tag with no value in the WHERE clause ```sql -> SELECT * FROM "h2o_feet" WHERE "location" !~ /./ -> +SELECT * FROM "h2o_feet" WHERE "location" !~ /./ + ``` The query selects all data from the `h2o_feet` measurement where the `location` @@ -2989,8 +2988,8 @@ The query returns the integer form of `water_level`'s float [field values](/ente #### Cast float field values to strings (this functionality is not supported) ```sql -> SELECT "water_level"::string FROM "h2o_feet" LIMIT 4 -> +SELECT "water_level"::string FROM "h2o_feet" LIMIT 4 + ``` The query returns no data as casting a float field value to a string is not diff --git a/content/enterprise_influxdb/v1/query_language/manage-database.md b/content/enterprise_influxdb/v1/query_language/manage-database.md index d57aa6efd..45b5848fe 100644 --- a/content/enterprise_influxdb/v1/query_language/manage-database.md +++ b/content/enterprise_influxdb/v1/query_language/manage-database.md @@ -87,8 +87,8 @@ If you attempt to create a database that already exists, InfluxDB does nothing a ##### Create a database ``` -> CREATE DATABASE "NOAA_water_database" -> +CREATE DATABASE "NOAA_water_database" + ``` The query creates a database called `NOAA_water_database`. @@ -97,8 +97,8 @@ The query creates a database called `NOAA_water_database`. ##### Create a database with a specific retention policy ``` -> CREATE DATABASE "NOAA_water_database" WITH DURATION 3d REPLICATION 1 SHARD DURATION 1h NAME "liquid" -> +CREATE DATABASE "NOAA_water_database" WITH DURATION 3d REPLICATION 1 SHARD DURATION 1h NAME "liquid" + ``` The query creates a database called `NOAA_water_database`. @@ -114,8 +114,8 @@ DROP DATABASE Drop the database NOAA_water_database: ```bash -> DROP DATABASE "NOAA_water_database" -> +DROP DATABASE "NOAA_water_database" + ``` A successful `DROP DATABASE` query returns an empty result. @@ -135,19 +135,19 @@ DROP SERIES FROM WHERE =' DROP SERIES FROM "h2o_feet" +DROP SERIES FROM "h2o_feet" ``` Drop series with a specific tag pair from a single measurement: ```sql -> DROP SERIES FROM "h2o_feet" WHERE "location" = 'santa_monica' +DROP SERIES FROM "h2o_feet" WHERE "location" = 'santa_monica' ``` Drop all points in the series that have a specific tag pair from all measurements in the database: ```sql -> DROP SERIES WHERE "location" = 'santa_monica' +DROP SERIES WHERE "location" = 'santa_monica' ``` A successful `DROP SERIES` query returns an empty result. @@ -168,25 +168,25 @@ DELETE FROM WHERE [=''] | [