Skip to content
Open
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
31 changes: 27 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,35 @@ on:

jobs:
test:
runs-on: ubuntu-latest
name: test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.25'
- run: go test ./... -v -count=1
- run: go build -o stacklit ./cmd/stacklit
- run: ./stacklit init
cache: true

- name: go vet
run: go vet ./...

- name: go test
run: go test ./... -race -count=1

- name: build
run: go build ./cmd/stacklit

- name: smoke test (generate)
run: go run ./cmd/stacklit generate --quiet
shell: bash

- name: smoke test (export markdown)
run: |
go run ./cmd/stacklit export -o stacklit-ci.md
test -s stacklit-ci.md
head -1 stacklit-ci.md | grep -q '^# '
shell: bash
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ stacklit diff # check if index is stale
stacklit serve # start MCP server
stacklit derive # print compact nav map (~250 tokens)
stacklit derive --inject claude # inject map into CLAUDE.md
stacklit export # print readable markdown overview
stacklit export -o stacklit.md # write markdown overview to a file
stacklit setup # auto-configure all detected AI tools
stacklit setup claude # configure Claude Code + MCP
stacklit setup cursor # configure Cursor + MCP
Expand Down
26 changes: 26 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ Regenerates `stacklit.html` and opens it in your browser.
| `stacklit derive` | Print compact navigation map (~250 tokens) to stdout |
| `stacklit derive --inject claude` | Inject map into CLAUDE.md |
| `stacklit derive --inject cursor` | Inject map into .cursorrules |
| `stacklit export` | Print a readable markdown overview to stdout |
| `stacklit export -o stacklit.md` | Write the markdown overview to a file |
| `stacklit setup` | Auto-detect and configure all AI tools |
| `stacklit setup claude` | Configure Claude Code (CLAUDE.md + MCP) |
| `stacklit setup cursor` | Configure Cursor (.cursorrules + MCP) |
Expand Down Expand Up @@ -150,6 +152,30 @@ The server auto-reloads when `stacklit.json` changes on disk.

---

## Exporting to markdown

`stacklit.json` is built for AI agents and tooling. When you want something a person can skim — a PR description, a GitHub issue, a Slack message — use the markdown export:

```bash
stacklit export # print to stdout
stacklit export -o stacklit.md # write to a file
```

The markdown contains:

- A title with the project name, language, file count, and total lines
- A language and framework summary table
- Entrypoints and key directories (when present)
- A modules table with purpose, size, and direct dependencies
- Per-module collapsible `<details>` blocks listing exports and types
- A dependency edge list, plus most-depended-on and isolated modules
- Hot files from the last 90 days (when git data is present)
- Hints: how to add a feature, the test command, env vars

Output is deterministic: the same `stacklit.json` produces byte-identical markdown across runs and machines, so it's safe to commit.

---

## Configuration

Create `.stacklitrc.json` in your project root (optional):
Expand Down
60 changes: 60 additions & 0 deletions internal/cli/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cli

import (
"encoding/json"
"fmt"
"os"

"github.com/glincker/stacklit/internal/renderer"
"github.com/glincker/stacklit/internal/schema"
"github.com/spf13/cobra"
)

func newExportCmd() *cobra.Command {
var format, source, output string

cmd := &cobra.Command{
Use: "export",
Short: "Export the index in a human-readable format",
Long: `Renders stacklit.json in a different format for sharing.

Currently supports markdown, which produces a readable project overview
suitable for pasting into PR descriptions, GitHub issues, or chat.

Examples:
stacklit export Print markdown to stdout
stacklit export --format md Same as above
stacklit export -o stacklit.md Write markdown to a file
stacklit export --source ./other.json Read from a non-default index`,
RunE: func(cmd *cobra.Command, args []string) error {
data, err := os.ReadFile(source)
if err != nil {
return fmt.Errorf("could not read %s: %w (run 'stacklit generate' first, or 'stacklit init')", source, err)
}
var idx schema.Index
if err := json.Unmarshal(data, &idx); err != nil {
return fmt.Errorf("could not parse %s: %w", source, err)
}

switch format {
case "md", "markdown":
if output == "" {
fmt.Print(renderer.RenderMarkdown(&idx))
return nil
}
if err := renderer.WriteMarkdown(&idx, output); err != nil {
return fmt.Errorf("could not write %s: %w", output, err)
}
fmt.Fprintf(cmd.OutOrStderr(), "Wrote %s\n", output)
return nil
default:
return fmt.Errorf("unknown format %q (supported: md, markdown)", format)
}
},
}

cmd.Flags().StringVar(&format, "format", "md", "Output format (md)")
cmd.Flags().StringVar(&source, "source", "stacklit.json", "Path to the index JSON")
cmd.Flags().StringVarP(&output, "output", "o", "", "Write to file instead of stdout")
return cmd
}
1 change: 1 addition & 0 deletions internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ func init() {
rootCmd.AddCommand(newServeCmd())
rootCmd.AddCommand(newDeriveCmd())
rootCmd.AddCommand(newSetupCmd())
rootCmd.AddCommand(newExportCmd())
}
Loading
Loading