Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions Build/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -152,27 +152,6 @@ module Documentation =
}
}

/// <summary>Prepends the <c>docs/static/llms.txt</c> header to <c>output/llms.txt</c>, which Nacara generates
/// as a verbatim copy of that same file, so the body appears twice. <c>output/llms-full.txt</c> does not
/// exist, so that half of the merge has no effect.</summary>
/// <remarks>
/// Written for fsdocs, which generated both files at the site root as a link inventory under such a heading.
/// </remarks>
let llms = input {
let! watch = Baked.Common.watch
return stage "llms" {
when' (not watch) "--watch is set"
run (fun ctx ->
let header = File.ReadAllText(Path.Combine(root, "docs", "static", "llms.txt")).TrimEnd()
for name in [ "llms.txt"; "llms-full.txt" ] do
let path = Path.Combine(root, "output", name)
if File.Exists path then
let body = File.ReadAllLines path |> Array.skipWhile (fun line -> line.Trim() = "" || line.StartsWith "# ")
File.WriteAllLines(path, Array.append [| header; "" |] body)
StageContext.writeLine ctx StdStream.Out $"merged docs/llms.txt into output/{name}")
}
}

module Commands =
let build =
command "build" {
Expand Down Expand Up @@ -231,7 +210,6 @@ module Commands =
Prelude.restore
ProjectManagement.buildAll
Documentation.generate
Documentation.llms
}
}

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,5 +303,5 @@ a patch bump move it breaks anything not rebuilt in the same pass with `Could no
- Public API goes in `[<AutoOpen>]` modules under `Partas.Build`; the model and engine stay in `Partas.Build.Internal`. A model type that appears in a public signature gets an abbreviation in `ConsumerTypes` (`Conductors.fs`), and a lookup a step needs gets a re-export in the public `StageContext` module.
- Human-readable console output uses `Terminal.ansi ()`, which follows the invocation writer. Plain host consoles disable CI profile enrichment to preserve plain text. GitHub workflow commands use `Terminal.out ()` directly to preserve one physical line, enabled by case-insensitive `GITHUB_ACTIONS=true` detection (see `WorkflowCommands` and `printError` in both context modules).
- The Nacara site (`docs/Site.fs`, `docs/docs.fsproj`) publishes every page under `docs/content/` and `docs/blog/`, plus the generated API reference, so internal working documents belong in `notes/` (as the `PLAN*.md` files do), not under `docs/`.
- The `.fsx` pages under `docs/content/` `#load` the library's sources in `<Compile>` order: a file added to `Partas.Build.fsproj` or `Partas.Build.Baked.fsproj` goes into all four lists, or the pages stop type-checking. Check a page with `dotnet fsi <page>.fsx` from its own directory. `docs/static/` is copied to the site root verbatim: `llms.txt` and `AGENTS-snippet.md` (the block a consumer pastes into its `AGENTS.md`, also packed into the `Partas.Build` package root). Nacara generates no `llms-full.txt`.
- Guides under `docs/content/` are Markdown. Compile changed F# examples against the current library in a scratch project before publishing; compile definitions without invoking the example workflows. Run the `docs` command to check navigation and links. `AgentFriendly` generates `llms.txt`, `llms-full.txt`, Markdown copies and alternate links; register link validation after it writes those files. `docs/static/` is copied verbatim, including `AGENTS-snippet.md`, which is also packed into the core package. Keep the agent index generated rather than adding a static copy or a post-build merge.
- XML docs carry `<example>` blocks on the entry points an agent hovers (`run`/`runLine`/`runSensitive`, `input`, `whenSome`, `Cmd.argIf`/`argWhenSome`/`cmd`, `stage`/`pipeline`/`command`/`rootCommand`/`rootCommandOfScript`, `Command.root`/`invoke`, `RootCommandDefinition.Invoke`, `RunResult`, `MachineOutput.json`, `Baked.Stages`). They are written to compile: an edit to one is checked by pasting it into a scratch script against the built library. Escape `<` as `&lt;` inside them; `GenerateDocumentationFile` is on and the build stays warning-free.
23 changes: 23 additions & 0 deletions docs/Directives.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Docs.Directives

open Feliz.ViewEngine
open Nacara.Core
open Nacara.Plugins

let private cards =
Directive.create "cards" Decode.node
|> Directive.render (fun _ _ contents ->
Html.div [ prop.className "pb-cards"; prop.children contents ])

let private card =
Directive.create "card" (Decode.object (fun get ->
{| Title = get.Required.Field "title" Decode.string
Href = get.Required.Field "href" Decode.string |}))
|> Directive.render (fun _ args contents ->
Html.a [
prop.className "pb-card"
prop.href args.Href
prop.children [ Html.strong args.Title; contents ]
])

let register = Directives.register [ cards; card ]
59 changes: 55 additions & 4 deletions docs/Site.fs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
module Docs.Site

open Feliz.ViewEngine
open System.IO
open Nacara.Core
open Nacara.Plugins
open Nacara.Theme
open Partas.Nacara.Theme

let theme =
Theme.defaults
|> Theme.favIcon "favicon.svg"
|> Theme.lightTokens (fun t -> { t with Primary = "#165c50"; ContentWidth = "48rem"; Radius = "0.6rem" })
|> Theme.darkTokens (fun t -> { t with Primary = "#7de0bd"; ContentWidth = "48rem"; Radius = "0.6rem" })
|> Theme.layerAfter "responsive" "partas" (File.ReadAllText(Path.Combine(__SOURCE_DIRECTORY__, "theme.css")))
|> Theme.navbar [
NavbarSection("Build", "build", "/build/")
NavbarSection("Guide", "build", "/build/")
NavbarSection("Extensions", "extensions", "/extensions/")
NavbarSection("External Annotations", "external-annotations", "/external-annotations/")
NavbarSection("Reference", "reference", "/reference/")
Expand All @@ -21,7 +26,42 @@ let theme =
NavbarIcon("GitHub", "https://github.com/shayanhabibi/Partas.Build", Icons.github)
]
|> Theme.editUrl "https://github.com/shayanhabibi/Partas.Build/edit/master/docs"
|> Theme.footer (Html.p [ Html.text "Built with Nacara" ])
|> Theme.footer (Html.p [ Html.text "Partas.Build · Build workflows in F# · Built with Nacara" ])
|> Theme.menu "build" [
Menu.section "Start here" [
Menu.page "Build/index.md"
Menu.page "Build/installation.md"
Menu.page "Build/getting-started.md"
]
Menu.section "Build workflows" [
Menu.page "Build/inputs.md"
Menu.page "Build/steps.md"
Menu.page "Build/composition.md"
Menu.page "Build/execution.md"
Menu.page "Build/baked.md"
]
Menu.section "Integrate and inspect" [
Menu.page "Build/agents.md"
Menu.page "Build/hosting.md"
Menu.page "Build/troubleshooting.md"
]
Menu.section "Reference" [
Menu.page "Build/CAPABILITIES.md"
Menu.page "Build/computation-expression-operations.md"
Menu.page "Build/workflow-reference.md"
Menu.page "Build/composition-reference.md"
]
]
|> Theme.menu "extensions" [
Menu.section "Extensions" [ Menu.page "extensions/index.md"; Menu.page "extensions/shipit.md" ]
]
|> Theme.menu "external-annotations" [
Menu.section "External annotations" [
Menu.page "external-annotations/index.md"
Menu.page "external-annotations/external-annotations-recipes.md"
Menu.page "external-annotations/external-annotations-api.md"
]
]
|> Theme.menu "blog" [
Menu.section "2026" [
Menu.section "September" [
Expand Down Expand Up @@ -58,10 +98,21 @@ let plugins =
>> FSharpApi.register apiOptions
>> Literate.register
>> TreeSitter.register
>> Docs.Directives.register
>> Sitemap.register
>> AgentFriendly.registerWith (
AgentFriendly.summary "Composable build workflows and command-line tools in F#."
>> AgentFriendly.details "Start with https://shayanhabibi.github.io/Partas.Build/build/getting-started.md. Commands derive their inputs and help from the stages they run. Inspect a consumer build with --help, --schema --json, or --explain --json before executing it. See https://shayanhabibi.github.io/Partas.Build/build/agents.md for JSON output and exit codes, and https://shayanhabibi.github.io/Partas.Build/AGENTS-snippet.md for repository instructions."
)
>> OgImage.registerWith (
OgImage.defaultImage (OgImage.image "/img/sun-ztu.jpeg" |> OgImage.withAlt "Partas.Build")
)
>> LightningCss.register
>> Esbuild.register
>> Nuglify.minifyHtml
>> Nuglify.minifyJs
// Validate after AgentFriendly writes Markdown and llms-full.txt. Canonical URLs point to
// this build, not the previously deployed site; local links are still validated normally.
>> LinkValidator.registerWith (LinkValidator.ignoring [ @"^https://shayanhabibi\.github\.io/Partas\.Build/" ])

let collections =
Site.collection content
Expand Down
8 changes: 4 additions & 4 deletions docs/content/Build/CAPABILITIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ order: 1

One line per custom operation on the four builders, per `Input` combinator, and per `Cmd` argument helper. The
[API reference](https://shayanhabibi.github.io/Partas.Build/reference/) has full signatures and remarks.
[Composing reusable blocks](composition.fsx) has worked examples.
[Composing reusable blocks](composition.md) has worked examples.

## How settings resolve

Expand Down Expand Up @@ -557,8 +557,8 @@ counterpart takes each of those options as an `InputSpec<_>` instead. A skip rep

## Reference

- [Overview](index.fsx) — the layers, and a first pipeline.
- [Composing reusable blocks](composition.fsx) — blocks, nesting, and composition across files.
- [Overview](index.md) — the layers, and a first pipeline.
- [Composing reusable blocks](composition.md) — blocks, nesting, and composition across files.
- [Hosting a build in a long-lived session](hosting.md) — `Command.invoke` from SageFs or any F# host.
- [Stage CE run overloads](computation-expression-operations.fsx).
- [Stage CE run overloads](computation-expression-operations.md).
- [API reference](https://shayanhabibi.github.io/Partas.Build/reference/) — full signatures and remarks.
43 changes: 43 additions & 0 deletions docs/content/Build/agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: Agents and JSON
description: Inspect a command and consume structured execution results.
category: Build
order: 8
---

Use the build's own command model to discover what it accepts and what it will run.

## Inspect before execution

```shell
dotnet run --project Build.fsproj -- build --help
dotnet run --project Build.fsproj -- build --schema --json
dotnet run --project Build.fsproj -- build --explain --json
```

`--help` describes registered inputs. `--schema --json` returns the command schema. `--explain --json` returns a static execution plan without running steps or effectful conditions. Text `--explain` may evaluate conditions such as a Git branch check.

## Consume a run result

```shell
dotnet run --project Build.fsproj -- build --json
```

A JSON run ends with one result document containing the outcome, exit code, reports, failures, and timings. Child processes may still print output before that document.

Detected AI environments default `--json` to true. Detection happens per invocation. `PARTAS_BUILD_DISABLE_AI=true` disables that automatic default; explicit `--json` still works. Use `--json false` to request text for an individual invocation.

## Handle exit codes

- `0`: success, including help and inspection.
- `1`: execution failed.
- `2`: invalid command or input; execution did not start.
- `130`: cancelled.

In an F# host, [invoke a reusable root](hosting.md) to receive a `RunResult` directly.

## Read these docs as Markdown

The site publishes [llms.txt](/Partas.Build/llms.txt), [llms-full.txt](/Partas.Build/llms-full.txt), and Markdown copies beside guide pages. Each HTML guide advertises its Markdown URL with an alternate link.

Copy the [agent instructions](https://shayanhabibi.github.io/Partas.Build/AGENTS-snippet.md) into a consumer repository to document how its build should be inspected.
44 changes: 44 additions & 0 deletions docs/content/Build/baked.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Baked stages
description: Reuse common .NET build operations and inputs.
category: Build
order: 7
---

`Partas.Build.Baked` provides ready-made stages for restore, build, clean, pack, publishing, and tests.

```fsharp
open Partas.Build
open Partas.Build.Baked

let projects = [ "src/MyLibrary/MyLibrary.fsproj" ]

let root = Command.root {
workingDir __SOURCE_DIRECTORY__
command "build" {
Command.pipeline {
Stages.restore "MyLibrary.slnx"
Stages.build projects
}
}
}
```

The stages register the inputs they need. Check `build --help` for the resulting flags.

## Reuse inputs

- `Baked.Dotnet.config`: build configuration.
- `Baked.NuGet.apiKey`: NuGet key, with an environment default.
- `Baked.Common.isCI`: CI detection and override.
- `Baked.SemVer.bump`: semantic version increment or explicit version.

Bind them with the same `input` block used for your own options.

## Choose a versioning workflow

The agnostic SemVer bump rewrites project `Version` and sets `AssemblyVersion` to the major version. It does not infer releases from commits.

For conventional commits and changelogs, use the [ShipIt bump](../extensions/shipit.md#use-the-shipit-backed-bump). It computes the release version and updates configured package versions together. Use one bump workflow per release.

Full signatures are in [Capabilities](CAPABILITIES.md#baked) and the [workflow reference](workflow-reference.md#baked-the-batteries).
Loading