RepoPilotOpen in app →

apple/pkl

A configuration as code language with rich validation and tooling.

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit today
  • 11 active contributors
  • Distributed ownership (top contributor 29% of recent commits)
Show all 6 evidence items →
  • Apache-2.0 licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/apple/pkl)](https://repopilot.app/r/apple/pkl)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/apple/pkl on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: apple/pkl

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/apple/pkl shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit today
  • 11 active contributors
  • Distributed ownership (top contributor 29% of recent commits)
  • Apache-2.0 licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live apple/pkl repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/apple/pkl.

What it runs against: a local clone of apple/pkl — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in apple/pkl | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>apple/pkl</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of apple/pkl. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/apple/pkl.git
#   cd pkl
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of apple/pkl and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "apple/pkl(\\.git)?\\b" \\
  && ok "origin remote is apple/pkl" \\
  || miss "origin remote is not apple/pkl (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "build.gradle.kts" \\
  && ok "build.gradle.kts" \\
  || miss "missing critical file: build.gradle.kts"
test -f "build-logic/src/main/kotlin/pklAllProjects.gradle.kts" \\
  && ok "build-logic/src/main/kotlin/pklAllProjects.gradle.kts" \\
  || miss "missing critical file: build-logic/src/main/kotlin/pklAllProjects.gradle.kts"
test -f ".github/workflows/main.yml" \\
  && ok ".github/workflows/main.yml" \\
  || miss "missing critical file: .github/workflows/main.yml"
test -f "README.adoc" \\
  && ok "README.adoc" \\
  || miss "missing critical file: README.adoc"
test -f "DEVELOPMENT.adoc" \\
  && ok "DEVELOPMENT.adoc" \\
  || miss "missing critical file: DEVELOPMENT.adoc"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/apple/pkl"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Pkl is a configuration as code language that generates JSON, YAML, TOML, and other formats with compile-time validation and type safety. It combines declarative configuration syntax with a full programming language runtime, enabling developers to build validated, reusable config templates without boilerplate or runtime errors. Multi-language monorepo: Core language runtime and CLI in Java/Kotlin (likely under pkl-cli/ or pkl-core/), JavaScript/CSS for web tooling, Shell scripts for CI/CD automation. GitHub Actions workflows use Pkl itself for job definitions (.github/jobs/), creating a self-hosting pattern. Separate ecosystem repositories (pkl-go, pkl-intellij, pkl-lsp) extend capabilities without core bloat.

👥Who it's for

Infrastructure engineers, DevOps teams, and platform builders who manage complex configurations (Kubernetes, cloud infrastructure, application configs) and need type safety, validation, and code reuse without switching between multiple config languages and validators.

🌱Maturity & risk

Production-ready with active development. The codebase shows substantial maturity (5.3M lines of code, primarily Java/Kotlin), comprehensive CI/CD via GitHub Actions, and multiple stable packages on Sonatype Repository. Regular releases and ecosystem tools (LSP, IDE plugins, Go/JVM bindings) indicate sustained investment.

Low risk for stable usage. The project is Apple-backed with clear governance (MAINTAINERS.adoc, CODE_OF_CONDUCT.md). Risk factors include: Kotlin/Java as implementation language (fewer contributors than Python/Go), reliance on GraalVM for native compilation, and the young language ecosystem means smaller community compared to established tools like Terraform or CUE.

Active areas of work

Active development visible via CI/CD workflows, release automation (.github/workflows/release.yml, release-branch.yml), CodeQL security scanning, and dependabot integration. The .github/jobs/ directory shows Pkl is used to generate its own CI configurations, indicating ongoing internal tooling improvements. Benchmark suite (bench/) suggests performance optimization work.

🚀Get running

Clone the repository: git clone https://github.com/apple/pkl.git && cd pkl. Check .java-version for required JDK (use jenv or download matching Java). Build with Gradle: ./gradlew build (Gradle wrapper present). See DEVELOPMENT.adoc for detailed setup steps and IDE configuration in .idea/.

Daily commands: Development: ./gradlew tasks lists all available Gradle tasks. Run tests: ./gradlew test. Build CLI: ./gradlew installDist creates distributions. IDE: Open project in IntelliJ; .idea/ config is committed. Benchmarks: ./gradlew -p bench jmh runs JMH performance tests.

🗺️Map of the codebase

  • build.gradle.kts — Root build configuration that orchestrates all Gradle tasks, dependencies, and multi-project setup for the entire Pkl codebase.
  • build-logic/src/main/kotlin/pklAllProjects.gradle.kts — Defines common build conventions applied across all projects, establishing consistent compilation, testing, and publishing standards.
  • .github/workflows/main.yml — Primary CI/CD pipeline that runs tests, builds artifacts, and validates the entire project on every commit.
  • README.adoc — Entry point documentation explaining Pkl's purpose, installation, and core concepts for all new contributors.
  • DEVELOPMENT.adoc — Essential guide for setting up the development environment, building from source, and running tests locally.
  • .java-version — Specifies the exact Java version required for building Pkl, critical for reproducible builds across team members.

🛠️How to make changes

Add a new Gradle plugin or build convention

  1. Create a new Kotlin file in build-logic/src/main/kotlin with pattern pkl*.gradle.kts naming (build-logic/src/main/kotlin/pklNewFeature.gradle.kts)
  2. Define the plugin class inheriting from Plugin<Project> and implement apply() method (build-logic/src/main/kotlin/NewFeaturePlugin.kt)
  3. Register the plugin in build-logic/build.gradle.kts gradlePlugin block (build-logic/build.gradle.kts)
  4. Apply the plugin in build.gradle.kts or individual subproject build files by ID (build.gradle.kts)

Add a new CI/CD workflow or job

  1. Create a new job definition using Pkl language in .github/jobs/ directory (.github/jobs/CustomJob.pkl)
  2. Reference the job in the appropriate workflow YAML file using Pkl composition (.github/workflows/main.yml)
  3. Add supporting shell scripts in .github/scripts/ if environment setup is needed (.github/scripts/custom_setup.sh)
  4. Update .github/PklProject to manage dependencies and project configuration (.github/PklProject)

Add a new performance benchmark

  1. Create a new benchmark class in bench/src/jmh/java/org/pkl/core/ extending JMH pattern (bench/src/jmh/java/org/pkl/core/NewBenchmark.java)
  2. Add test fixtures as .pkl files in bench/src/jmh/resources/org/pkl/core/ (bench/src/jmh/resources/org/pkl/core/benchmark_input.pkl)
  3. Annotate benchmark methods with @Benchmark, @BenchmarkMode, and @Fork from JMH (bench/src/jmh/java/org/pkl/core/NewBenchmark.java)
  4. Run via Gradle: ./gradlew :bench:jmh to execute and generate results (bench/bench.gradle.kts)

🔧Why these technologies

  • Gradle (Kotlin DSL) — Powerful multi-project build system enabling convention-based plugin development, custom task composition, and reproducible builds across macOS/Linux/Windows
  • GraalVM Native Image — Compiles Pkl to self-contained native executables, eliminating JVM startup overhead and enabling distribution as single binaries without Java installation
  • JMH (Java Microbenchmarking Harness) — Provides accurate performance measurements isolated from JVM JIT warmup and garbage collection interference
  • GitHub Actions + Pkl — Pkl is used to generate CI/CD workflows as code, allowing reusable job templates and reducing YAML duplication
  • Java 11+ with JSpecify — Leverages modern Java features while using JSpecify annotations for nullness tracking and improved IDE support

⚖️Trade-offs already made

  • Multi-project Gradle build with shared build-logic module

    • Why: Enables consistent conventions across all subprojects without duplication
    • Consequence: Steeper learning curve for contributors; changes to build-logic affect all projects
  • Using Pkl to define CI workflows instead of pure YAML

    • Why: Demonstrates Pkl as a practical tool for real infrastructure and reduces workflow boilerplate
    • Consequence: Requires contributors to understand Pkl syntax; build definition is less visible in standard GitHub UI
  • Compiling to native binary via GraalVM

    • Why: Provides instant startup and no JVM dependency; ideal for CLI tools
    • Consequence: Native image build adds 3–5 minutes per release; reflection must be declared in metadata
  • Comprehensive benchmarking suite (JMH)

    • Why: Catches performance regressions early before release
    • Consequence: Benchmark runs add overhead to CI; requires baseline comparisons

🚫Non-goals (don't propose these)

  • Does not provide cloud runtime infrastructure; Pkl is a configuration language, not a runtime system
  • Does not include built-in authentication or secrets management; relies on external tools
  • Does not support dynamic module loading at runtime; all modules must be resolved during initialization
  • Does not implement a standalone package manager; focuses on language design and tooling

🪤Traps & gotchas

JDK version is pinned in .java-version—using a different version causes build failures (check with java -version). GraalVM is required for native binary builds, not standard JDK. Pre-commit hooks in .githooks/ must be installed manually (git config core.hooksPath .githooks) to avoid CI failures on code style. The codebase uses Kotlin for newer modules but Java for older ones, requiring familiarity with both. GitHub Actions workflows are generated from Pkl source in .github/jobs/—editing .yml files directly will be overwritten.

🏗️Architecture

💡Concepts to learn

  • Configuration as Code (CaC) — Pkl's core premise is treating configs like source code with validation, version control, and reuse; understanding CaC philosophy is essential to using Pkl effectively.
  • Type-driven validation — Pkl validates configuration at compile-time using a type system (not runtime); this is fundamental to how it prevents config errors before deployment.
  • Template inheritance and mixins — Pkl uses object-oriented patterns (inheritance, mixins) to achieve DRY config reuse; critical for understanding how to write maintainable Pkl code.
  • GraalVM native image compilation — Pkl CLI is compiled to native binaries via GraalVM, not distributed as JARs; this affects how the project builds distribution artifacts and requires understanding GraalVM constraints.
  • Language Server Protocol (LSP) — Pkl implements LSP (see apple/pkl-lsp) to provide IDE support; understanding LSP is key for contributing to editor integrations.
  • Declarative vs. imperative config — Pkl blurs the line between declarative (JSON/YAML style) and imperative (programming language) config; understanding this hybrid is crucial for idiomatic Pkl code.
  • Multi-format code generation — Pkl evaluates to a single internal representation but can emit JSON, YAML, TOML, XML, or custom formats; the architecture must support pluggable formatters.
  • cue-lang/cue — CUE is a direct competitor offering configuration as code with validation; comparison and cross-learning opportunity.
  • hashicorp/terraform — Terraform HCL is the industry standard for IaC; Pkl targets similar use cases and often needs to generate Terraform configs.
  • apple/pkl-go — Official Go language bindings; required if embedding Pkl evaluator in Go applications.
  • apple/pkl-intellij — JetBrains IDE plugins for Pkl language support; essential for developer experience in IntelliJ/GoLand/etc.
  • apple/pkl-lsp — Language Server Protocol implementation for Pkl; enables editor support in VSCode, Vim, Emacs, and other LSP-compatible editors.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for Pkl GitHub Actions workflow generation

The repo uses Pkl itself to define GitHub Actions workflows (.github/jobs/*.pkl and .github/workflows/lockfile.yml). However, there are no visible integration tests validating that the Pkl configuration files generate valid GitHub Actions YAML. This is a self-referential testing opportunity that would catch configuration regressions early and demonstrate Pkl's capability for infrastructure-as-code.

  • [ ] Create integration test suite in a new directory like pkl-github-actions-tests/ or add to existing test structure
  • [ ] Parse .github/jobs/.pkl files and validate generated workflows match .github/workflows/.yml
  • [ ] Add validation that generated YAML conforms to GitHub Actions schema
  • [ ] Integrate test into .github/workflows/build.yml or create dedicated workflow in .github/workflows/validate-pkl-config.yml
  • [ ] Document the test pattern in DEVELOPMENT.adoc as an example of Pkl testing best practices

Add comprehensive benchmark suite documentation and automated performance regression detection

The repo has a benchmarking infrastructure in bench/ with JMH benchmarks (ParserBenchmark.java, Fibonacci, ListSort), but there's no documented process for running them, analyzing results, or detecting performance regressions. New contributors cannot easily understand how to contribute performance-sensitive code changes or validate their PRs don't regress performance.

  • [ ] Create BENCHMARK.md documenting how to run bench/ tests with JMH (gradle jmh, result interpretation, etc.)
  • [ ] Add a GitHub Actions workflow (.github/workflows/benchmark.yml) that runs benchmarks on PR pushes and compares against baseline
  • [ ] Create a simple baseline storage mechanism (e.g., commit baseline results to a benchmark-results branch or use action artifacts)
  • [ ] Document in CONTRIBUTING.adoc which changes are performance-sensitive and require benchmark validation
  • [ ] Add pre-commit hook guidance in .github/hooks/pre-commit or documentation

Add missing platform-specific build documentation and validation for native executables

The repo contains platform-specific build scripts (.github/scripts/cc_macos_amd64.sh, install_musl.sh) and native build jobs (BuildNativeJob.pkl), but there's no comprehensive documentation on cross-platform native builds, musl/glibc requirements, or troubleshooting. This creates friction for contributors trying to build native executables on different platforms.

  • [ ] Create or enhance DEVELOPMENT.adoc with 'Building Native Executables' section covering macOS (amd64/arm64), Linux (glibc/musl), and Windows requirements
  • [ ] Document the purpose of .github/scripts/install_musl.sh and cc_macos_amd64.sh with concrete examples of when/how to use them
  • [ ] Add validation script (e.g., scripts/verify-native-build-env.sh) that checks for required tools (musl-gcc, target SDKs) and provides clear error messages
  • [ ] Reference the native build job requirements from BuildNativeJob.pkl in the documentation
  • [ ] Update .idea/scopes/AllProjects.xml or create native build profile documentation if relevant

🌿Good first issues

  • Add test coverage for the Pkl standard library functions in pkl-core/src/test/ (scan existing tests to find functions with missing edge cases and add parameterized tests using JUnit5).
  • Expand language reference documentation: the .adoc files in the main repo document standard library; pick an undocumented builtin function and add examples and error cases to the appropriate .adoc file.
  • Create a simple example in the ecosystem: add a new example under pkl-k8s-examples/ showing how to configure a common Kubernetes object (e.g., Ingress, StatefulSet) with Pkl; file an issue first to avoid duplication.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 38733e5 — Fix parsing of dependency notation URIs (#1570) (bioball)
  • 8ff03cf — Bump gradle-wrapper from 9.4.1 to 9.5.0 (#1575) (dependabot[bot])
  • be8366a — Bump jline from 4.0.12 to 4.0.14 (#1574) (dependabot[bot])
  • 8a4821c — Power assertions: change source section check to an assert (#1572) (HT154)
  • b7ba6a8 — Fix pkl:test fact power assertions when member source section is unavailable (#1571) (HT154)
  • 9c1a9cb — Bump kotlinToolchain from 2.3.20 to 2.3.21 (#1567) (dependabot[bot])
  • 5d4bac8 — Bump com.uber.nullaway:nullaway from 0.13.2 to 0.13.4 (#1568) (dependabot[bot])
  • 4a25320 — Fix import/read verification when encountering glob wildcards (#1559) (bioball)
  • df063f1 — Added pkg module key factory and resource reader to project loading (#1547) (netvl)
  • d3a3a14 — Fix CRLF handling in line continuation escapes (#1564) (KushalP)

🔒Security observations

The Pkl project demonstrates a reasonably strong security posture. The codebase shows no obvious hardcoded secrets, SQL injection risks, XSS vulnerabilities, or major infrastructure misconfigurations in the visible file structure. The project has established a SECURITY.md policy for vulnerability reporting, though it could be enhanced with more direct contact information. No dependency file content was provided for analysis. Main recommendations include: (1) strengthening the security reporting process with a dedicated contact, (2) reviewing pre-commit hook configuration practices, and (3) conducting regular audits of CI/CD and build scripts. The project would benefit from implementing automated secret scanning in the CI/CD pipeline and maintaining a dependency vulnerability scanning process.

  • Low · Incomplete Security Policy — SECURITY.md. The SECURITY.md file directs security vulnerability reports to Apple's general vulnerability form rather than providing a dedicated security contact or email address. This may cause delays in vulnerability reporting and response. Fix: Add a direct security contact email (e.g., security@pkl-lang.org) and establish a clear responsible disclosure timeline (e.g., 90 days) in SECURITY.md.
  • Low · Git Pre-commit Hook Present — .githooks/pre-commit. A .githooks/pre-commit file exists in version control. Pre-commit hooks should typically not be committed as they may be bypassed or contain sensitive patterns. Developers might bypass these hooks using git commit --no-verify. Fix: Move pre-commit hook configuration to a shared, enforced mechanism (e.g., Husky with Node.js, or document hook setup in CONTRIBUTING.adoc). Consider using server-side enforcement on the repository.
  • Low · Build Scripts in Repository Root — .github/scripts/. Build and CI/CD scripts in .github/scripts/ (.sh files) are committed to the repository. While common practice, ensure these scripts are regularly audited for injection vulnerabilities and do not contain credentials or sensitive paths. Fix: Implement script signing, code review requirements for script changes, and scan for hardcoded credentials in CI/CD scripts using tools like TruffleHog or GitGuardian.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · apple/pkl — RepoPilot