tinkerdown

package module
v0.0.0-...-c6922af Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 2, 2026 License: MIT Imports: 20 Imported by: 0

README

Tinkerdown

Build data-driven apps with markdown

Tinkerdown is a CLI tool for creating interactive, data-driven applications using markdown files. Connect to databases, APIs, and files with zero boilerplate. Built on LiveTemplate.

Quick Start

# Install
go install github.com/livetemplate/tinkerdown/cmd/tinkerdown@latest

# Create a new app
tinkerdown new myapp
cd myapp

# Run the app
tinkerdown serve
# Open http://localhost:8080

What You Can Build

Write a single markdown file with frontmatter configuration:

---
title: Task Manager
sources:
  tasks:
    type: sqlite
    path: ./tasks.db
    query: SELECT * FROM tasks
---

# Task Manager

<table lvt-source="tasks" lvt-columns="title,status,due_date" lvt-actions="Complete,Delete">
</table>

<form lvt-submit="AddTask">
  <input name="title" placeholder="New task" required>
  <button type="submit">Add</button>
</form>

Run tinkerdown serve and get a fully interactive app with database persistence.

Key Features

  • Single-file apps: Everything in one markdown file with frontmatter
  • 8 data sources: SQLite, JSON, CSV, REST APIs, PostgreSQL, exec scripts, markdown, WASM
  • Auto-rendering: Tables, selects, and lists generated from data
  • Real-time updates: WebSocket-powered reactivity
  • Zero config: tinkerdown serve just works
  • Hot reload: Changes reflect immediately

Data Sources

Define sources in your page's frontmatter:

---
sources:
  tasks:
    type: sqlite
    path: ./tasks.db
    query: SELECT * FROM tasks

  users:
    type: rest
    from: https://api.example.com/users

  config:
    type: json
    path: ./_data/config.json
---
Type Description Example
sqlite SQLite databases lvt-source-sqlite-test
json JSON files lvt-source-file-test
csv CSV files lvt-source-file-test
rest REST APIs lvt-source-rest-test
pg PostgreSQL lvt-source-pg-test
exec Shell commands lvt-source-exec-test
markdown Markdown files markdown-data-todo
wasm WASM modules lvt-source-wasm-test

Auto-Rendering

Generate HTML automatically from data sources:

<!-- Table with actions -->
<table lvt-source="tasks" lvt-columns="title,status" lvt-actions="Edit,Delete">
</table>

<!-- Select dropdown -->
<select lvt-source="categories" lvt-value="id" lvt-label="name">
</select>

<!-- List -->
<ul lvt-source="items" lvt-field="name">
</ul>

See Auto-Rendering Guide for full details.

Interactive Attributes

Attribute Description
lvt-source Connect element to a data source
lvt-click Handle click events
lvt-submit Handle form submissions
lvt-change Handle input changes
lvt-confirm Show confirmation dialog before action
lvt-data-* Pass data with actions

See lvt-* Attributes Reference for the complete list.

Configuration

Recommended: Configure in frontmatter (single-file apps):

---
title: My App
sources:
  tasks:
    type: sqlite
    path: ./tasks.db
    query: SELECT * FROM tasks
styling:
  theme: clean
---

For complex apps: Use tinkerdown.yaml for shared configuration:

# tinkerdown.yaml - for multi-page apps with shared sources
server:
  port: 3000
sources:
  shared_data:
    type: rest
    from: ${API_URL}
    cache:
      ttl: 5m

See Configuration Reference for when to use each approach.

AI-Assisted Development

Tinkerdown works great with AI assistants. Describe what you want:

Create a task manager with SQLite storage,
a table showing tasks with title/status/due date,
a form to add tasks, and delete buttons on each row.

See AI Generation Guide for tips on using Claude Code and other AI tools.

Documentation

Getting Started:

Guides:

Reference:

Planning:

Development

git clone https://github.com/livetemplate/tinkerdown.git
cd tinkerdown
go mod download
go test ./...
go build -o tinkerdown ./cmd/tinkerdown

License

MIT

Contributing

Contributions welcome! See ROADMAP.md for planned features and current priorities.

Documentation

Overview

Package tinkerdown provides the core library for building interactive documentation with markdown files and embedded executable code blocks.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseMarkdown

func ParseMarkdown(content []byte) (*Frontmatter, []*CodeBlock, string, error)

ParseMarkdown parses a markdown file and extracts frontmatter and code blocks.

func ParseMarkdownWithPartials

func ParseMarkdownWithPartials(content []byte, baseDir string) (*Frontmatter, []*CodeBlock, string, error)

ParseMarkdownWithPartials parses markdown with partial file support. baseDir is used to resolve relative paths in {{partial "file.md"}} directives.

func ProcessPartials

func ProcessPartials(content []byte, baseDir string, seen map[string]bool) ([]byte, error)

ProcessPartials recursively processes {{partial "file.md"}} directives in content. baseDir is the directory to resolve relative paths from. seen tracks already-included files to prevent circular dependencies.

Types

type Action

type Action struct {
	Kind      string              `yaml:"kind"`                // Action kind: "sql", "http", "exec"
	Source    string              `yaml:"source,omitempty"`    // For sql: source name to execute against
	Statement string              `yaml:"statement,omitempty"` // For sql: SQL statement with :param placeholders
	URL       string              `yaml:"url,omitempty"`       // For http: request URL (supports template expressions)
	Method    string              `yaml:"method,omitempty"`    // For http: HTTP method (default: POST)
	Body      string              `yaml:"body,omitempty"`      // For http: request body template
	Cmd       string              `yaml:"cmd,omitempty"`       // For exec: command to run
	Params    map[string]ParamDef `yaml:"params,omitempty"`    // Parameter definitions
	Confirm   string              `yaml:"confirm,omitempty"`   // Confirmation message (triggers dialog)
}

Action defines a custom action that can be triggered via lvt-click.

type BlocksConfig

type BlocksConfig struct {
	AutoID          bool   `yaml:"auto_id"`
	IDFormat        string `yaml:"id_format"`
	ShowLineNumbers bool   `yaml:"show_line_numbers"`
}

BlocksConfig represents code block display configuration.

type CodeBlock

type CodeBlock struct {
	Type     string            // "server", "wasm", "lvt"
	Language string            // "go", etc.
	Flags    []string          // "readonly", "editable"
	Metadata map[string]string // id, state, etc.
	Content  string
	Line     int // Line number in source file
}

CodeBlock represents a code block extracted from markdown.

type FeaturesConfig

type FeaturesConfig struct {
	HotReload bool `yaml:"hot_reload"`
	Sidebar   bool `yaml:"sidebar"` // Show navigation sidebar
}

FeaturesConfig represents feature flags.

type Frontmatter

type Frontmatter struct {
	// Page metadata
	Title   string      `yaml:"title"`
	Type    string      `yaml:"type"`    // tutorial, guide, reference, playground
	Persist PersistMode `yaml:"persist"` // none, localstorage, server
	Steps   int         `yaml:"steps"`

	// Top-level convenience options
	Sidebar *bool `yaml:"sidebar,omitempty"` // Show navigation sidebar (overrides features.sidebar)

	// Config options (can override livemdtools.yaml)
	Sources  map[string]SourceConfig `yaml:"sources,omitempty"`
	Actions  map[string]Action       `yaml:"actions,omitempty"`
	Styling  *StylingConfig          `yaml:"styling,omitempty"`
	Blocks   *BlocksConfig           `yaml:"blocks,omitempty"`
	Features *FeaturesConfig         `yaml:"features,omitempty"`

	// Computed expressions found in the markdown content (populated during parsing)
	// Map of expression ID to expression string (e.g., "expr-1" -> "count(tasks where done)")
	Expressions map[string]string `yaml:"-"`

	// Schedule tokens found in the markdown content (populated during parsing)
	Schedules []*schedule.Token `yaml:"-"`

	// Imperative commands (Notify, Run action) found in the markdown (populated during parsing)
	Imperatives []*schedule.Imperative `yaml:"-"`

	// Schedule parsing warnings (populated during parsing)
	ScheduleWarnings []schedule.ParseWarning `yaml:"-"`
}

Frontmatter represents the YAML frontmatter at the top of a markdown file.

type InteractiveBlock

type InteractiveBlock struct {
	ID       string
	StateRef string // References a ServerBlock ID
	Template *livetemplate.Template
	Store    interface{} // State object with action methods (uses method dispatch)
	Content  string      // Template content
	Metadata map[string]string
}

InteractiveBlock represents a live UI component powered by server state. Each block is a mini livetemplate instance.

type MessageEnvelope

type MessageEnvelope struct {
	BlockID string          `json:"blockID"`
	Action  string          `json:"action"`
	Data    json.RawMessage `json:"data"`
}

MessageEnvelope wraps messages with block ID routing information.

type MessageRouter

type MessageRouter struct {
	// contains filtered or unexported fields
}

MessageRouter routes messages to appropriate blocks based on blockID.

func NewMessageRouter

func NewMessageRouter(ps *PageState) *MessageRouter

NewMessageRouter creates a new message router for a page state.

func (*MessageRouter) Route

func (mr *MessageRouter) Route(envelope *MessageEnvelope) (*ResponseEnvelope, error)

Route routes an incoming message to the appropriate handler.

type Page

type Page struct {
	ID                string
	Title             string
	Type              string // tutorial, guide, reference, playground
	SourceFile        string // Absolute path to source .md file (for error messages)
	Sidebar           *bool  // nil = use default, true/false = explicit override
	Config            PageConfig
	StaticHTML        string
	ServerBlocks      map[string]*ServerBlock
	WasmBlocks        map[string]*WasmBlock
	InteractiveBlocks map[string]*InteractiveBlock
	// Expressions maps expression IDs to expression strings (e.g., "expr-0" -> "count(tasks where done)")
	// These are computed expressions found in inline code spans like `=count(tasks where done)`
	Expressions map[string]string

	// Schedules contains parsed schedule tokens found in the markdown content
	Schedules []*schedule.Token

	// Imperatives contains parsed imperative commands (Notify, Run action) from the markdown
	Imperatives []*schedule.Imperative

	// ScheduleWarnings contains any warnings generated during schedule parsing
	ScheduleWarnings []schedule.ParseWarning
}

Page represents a parsed tinkerdown tutorial/guide/playground.

func BuildPage

func BuildPage(id, sourceFile string, content []byte) (*Page, error)

BuildPage creates a Page from raw content with a specified ID and source file. This is useful for testing and programmatic page creation. The content should be valid markdown with optional frontmatter.

func New

func New(id string) *Page

New creates a new Page with the given ID.

func ParseFile

func ParseFile(path string) (*Page, error)

ParseFile parses a markdown file and creates a Page.

func ParseString

func ParseString(content string) (*Page, error)

ParseString parses markdown content from a string and creates a Page. This is useful for the playground where content comes from user input.

func (*Page) ParseFiles

func (p *Page) ParseFiles(files ...string) error

ParseFiles parses markdown files and updates the Page.

type PageConfig

type PageConfig struct {
	// Page behavior
	Persist   PersistMode
	MultiStep bool
	StepCount int

	// Effective config (merged from frontmatter + site config)
	Sources  map[string]SourceConfig
	Actions  map[string]Action
	Styling  StylingConfig
	Blocks   BlocksConfig
	Features FeaturesConfig
}

PageConfig contains configuration for a page.

func (*PageConfig) MergeFromFrontmatter

func (pc *PageConfig) MergeFromFrontmatter(fm *Frontmatter)

MergeFromFrontmatter applies frontmatter config options to PageConfig. Frontmatter values take precedence over any existing values.

type PageState

type PageState struct {

	// Current step for multi-step tutorials
	CurrentStep int

	// Interactive block states (stored as generic interfaces)
	// State objects use method dispatch for action handling
	InteractiveStates map[string]interface{}

	// Code edits for WASM blocks (blockID -> code)
	CodeEdits map[string]string

	// Completed steps tracking
	CompletedSteps []int
	// contains filtered or unexported fields
}

PageState manages the runtime state of a livemdtools session.

func NewPageState

func NewPageState(page *Page) *PageState

NewPageState creates a new page state for a session.

func (*PageState) HandleAction

func (ps *PageState) HandleAction(action string, data map[string]interface{}) error

HandleAction processes page-level actions.

type ParamDef

type ParamDef struct {
	Type     string `yaml:"type,omitempty"`     // Parameter type: "string", "number", "date", "bool"
	Required bool   `yaml:"required,omitempty"` // Whether the parameter is required
	Default  string `yaml:"default,omitempty"`  // Default value
}

ParamDef defines a parameter for an action.

type ParseError

type ParseError struct {
	File    string // Source file path
	Line    int    // Line number (1-indexed)
	Column  int    // Column number (1-indexed, optional)
	Message string // Error message
	Code    string // Offending code snippet
	Hint    string // Helpful suggestion
	Related string // Related information (e.g., "State 'foo' defined at line 20")
}

ParseError represents a detailed parsing error with context.

func NewParseError

func NewParseError(file string, line int, message string) *ParseError

NewParseError creates a new ParseError.

func (*ParseError) Error

func (e *ParseError) Error() string

Error implements the error interface.

func (*ParseError) Format

func (e *ParseError) Format() string

Format returns a nicely formatted error message with context.

func (*ParseError) WithColumn

func (e *ParseError) WithColumn(col int) *ParseError

WithColumn adds column information to the error.

func (*ParseError) WithHint

func (e *ParseError) WithHint(hint string) *ParseError

WithHint adds a helpful hint to the error.

func (*ParseError) WithRelated

func (e *ParseError) WithRelated(related string) *ParseError

WithRelated adds related information to the error.

type PersistMode

type PersistMode string

PersistMode determines how tutorial state is persisted.

const (
	PersistNone         PersistMode = "none"
	PersistLocalStorage PersistMode = "localstorage"
	PersistServer       PersistMode = "server"
)

type ResponseEnvelope

type ResponseEnvelope struct {
	BlockID string                 `json:"blockID"`
	Tree    map[string]interface{} `json:"tree,omitempty"`
	Meta    map[string]interface{} `json:"meta"`
}

ResponseEnvelope wraps responses with block ID routing information.

type ServerBlock

type ServerBlock struct {
	ID       string
	Language string // Currently only "go"
	Content  string
	Metadata map[string]string
}

ServerBlock represents author-written server-side code. This code is trusted, pre-compiled, and powers interactive blocks.

type SourceConfig

type SourceConfig struct {
	Type        string            `yaml:"type"`                   // exec, pg, rest, csv, json, markdown, sqlite, wasm
	Cmd         string            `yaml:"cmd,omitempty"`          // For exec type
	Query       string            `yaml:"query,omitempty"`        // For pg type
	From        string            `yaml:"from,omitempty"`         // For rest type: API endpoint URL
	File        string            `yaml:"file,omitempty"`         // For csv/json/markdown types
	Anchor      string            `yaml:"anchor,omitempty"`       // For markdown: section anchor (e.g., "#todos")
	DB          string            `yaml:"db,omitempty"`           // For sqlite: database file path
	Table       string            `yaml:"table,omitempty"`        // For sqlite: table name
	Path        string            `yaml:"path,omitempty"`         // For wasm: path to .wasm file
	Headers     map[string]string `yaml:"headers,omitempty"`      // For rest: HTTP headers (env vars expanded)
	QueryParams map[string]string `yaml:"query_params,omitempty"` // For rest: URL query parameters
	ResultPath  string            `yaml:"result_path,omitempty"`  // For rest: dot-path to extract array (e.g., "data.items")
	Readonly    *bool             `yaml:"readonly,omitempty"`     // For markdown/sqlite: read-only mode (default: true)
	Options     map[string]string `yaml:"options,omitempty"`
	Manual      bool              `yaml:"manual,omitempty"`    // For exec: require Run button click
	Format      string            `yaml:"format,omitempty"`    // For exec: output format (json, lines, csv)
	Delimiter   string            `yaml:"delimiter,omitempty"` // For exec CSV: field delimiter (default ",")
	Env         map[string]string `yaml:"env,omitempty"`       // For exec: environment variables (env vars expanded)
	Timeout     string            `yaml:"timeout,omitempty"`   // For exec/rest: timeout (e.g., "30s", "1m")
}

SourceConfig represents a data source configuration for lvt-source blocks.

type StatusType

type StatusType string

StatusType represents the type of status banner

const (
	StatusSuccess StatusType = "success"
	StatusWarning StatusType = "warning"
	StatusError   StatusType = "error"
	StatusInfo    StatusType = "info"
)

type StylingConfig

type StylingConfig struct {
	Theme        string `yaml:"theme"`
	PrimaryColor string `yaml:"primary_color"`
	Font         string `yaml:"font"`
}

StylingConfig represents styling/theme configuration.

type Tab

type Tab struct {
	Name   string // Display name of the tab
	Filter string // Filter expression (empty for "All" tab)
}

Tab represents a single tab definition parsed from a heading.

type WasmBlock

type WasmBlock struct {
	ID            string
	Language      string // Currently only "go"
	DefaultCode   string
	ShowRunButton bool
	Metadata      map[string]string
}

WasmBlock represents student-editable code that runs in the browser. This code is untrusted and never sent to the server.

Directories

Path Synopsis
cmd
tinkerdown command
Command tinkerdown is the CLI tool for creating and serving interactive documentation.
Command tinkerdown is the CLI tool for creating and serving interactive documentation.
docs
research/examples/custom-sources/go command
Change freeze checker for tinkerdown Checks if deploys are allowed based on calendar rules
Change freeze checker for tinkerdown Checks if deploys are allowed based on calendar rules
examples
lvt-source-wasm-test/sources command
Example WASM source module for tinkerdown.
Example WASM source module for tinkerdown.
internal
assets
Package assets embeds the client JavaScript, CSS, and vendor libraries
Package assets embeds the client JavaScript, CSS, and vendor libraries
blocks
Package blocks provides block type registry and management.
Package blocks provides block type registry and management.
cache
Package cache provides caching functionality for data sources.
Package cache provides caching functionality for data sources.
markdown
Package markdown provides markdown parsing functionality for livemdtools.
Package markdown provides markdown parsing functionality for livemdtools.
output
Package output provides notification outputs for tinkerdown.
Package output provides notification outputs for tinkerdown.
runtime
Package runtime provides expression evaluation for computed expressions.
Package runtime provides expression evaluation for computed expressions.
schedule
Package schedule provides parsing and execution of schedule tokens.
Package schedule provides parsing and execution of schedule tokens.
security
Package security provides shared security validation functions.
Package security provides shared security validation functions.
server
Package server provides HTTP handlers for the tinkerdown server.
Package server provides HTTP handlers for the tinkerdown server.
slug
Package slug provides heading-to-anchor conversion (GitHub-style slugification).
Package slug provides heading-to-anchor conversion (GitHub-style slugification).
source
Package source provides data source implementations for lvt-source blocks.
Package source provides data source implementations for lvt-source blocks.
state
Package state provides state management for livemdtools.
Package state provides state management for livemdtools.
wasm
Package wasm provides WASM-based data source support for tinkerdown.
Package wasm provides WASM-based data source support for tinkerdown.
pkg
embedded
Package embedded provides functionality for running tinkerdown apps from embedded filesystems.
Package embedded provides functionality for running tinkerdown apps from embedded filesystems.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL