<h1 align="center">
<a href="https://prompts.chat">
Loading actions...
<a href="https://prompts.chat">
TypeScript and ESLint rules that MUST be followed when creating, modifying, or reviewing any file under apps/frontend/, including .ts, .tsx, .js, and .jsx files. Also apply when discussing frontend linting, type safety, or ESLint configuration.
risks
This repository contains nocturnal, a Go CLI tool for specification-driven development with AI agent integration via MCP (Model Context Protocol).
Nocturnal manages specifications, proposals, rules, maintenance tasks, and third-party documentation in a structured workspace. It exposes project context to AI agents through an MCP server.
# Build & Run
make build # Build binary
make install # Build and install to ~/.local/bin
go run . <command> # Run without building
# Testing & Quality
make test # Run all tests with race detection
go test -v ./... # Run all tests
go test -v -run TestName ./.. # Run a single test by name
# Code Quality
make fmt # Format code (go fmt)
make lint # Run linter (go vet)
make deps # Download and tidy dependencies
nocturnal/
├── main.go # Entry point, sets version/build vars
├── cmd/ # CLI commands (Cobra-based)
│ ├── root.go # Root command and shell completion
│ ├── agent.go # Agent context commands (current, project, specs)
│ ├── docs.go # Third-party documentation management
│ ├── mcp.go # MCP server with tools and prompts
│ ├── spec.go # Specification and proposal commands
│ ├── maintenance.go # Recurring maintenance task management
│ ├── stats.go # Project statistics and metrics
│ ├── graph.go # Proposal dependency graph visualization
│ ├── config.go # Configuration management
│ ├── state.go # State persistence (active proposals, etc.)
│ ├── git.go # Git snapshot and commit management
│ ├── ui.go # Terminal output styling
│ ├── util.go # Helper functions
│ └── templates/ # Embedded templates and help text
├── docs/ # Project documentation
└── spec/ # Workspace (created per-project via `nocturnal spec init`)
├── proposal/ # Active proposals
├── section/ # Completed specifications
├── archive/ # Archived design/implementation docs
├── rule/ # Project-wide rules
├── maintenance/ # Recurring maintenance items
├── third/ # Third-party library documentation
├── project.md # Project design overview
├── nocturnal.yaml # Configuration file
└── .nocturnal.json # State file (active proposals, hashes, etc.)
Order imports in three groups, separated by blank lines:
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
go fmt (via make fmt) before committing| Element | Convention | Example |
|---|---|---|
| Packages | lowercase, short | cmd, ui |
| Files | lowercase, underscores ok | format.go, agent.go |
| Functions | PascalCase (exported) | Execute(), Success() |
| Functions | camelCase (unexported) | runTodoWrite(), copyFile |
| Variables | camelCase | specPath, proposalPath |
| Constants | camelCase (unexported) | specDir, ruleDir |
| Structs | PascalCase | DocComponent |
| Interfaces | PascalCase, -er suffix if verb | Reader, Formatter |
fmt.Errorf("context: %w", err)os.IsNotExist(err) for file existence checks// Good
content, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return "", fmt.Errorf("file not found: %s", path)
}
return "", fmt.Errorf("failed to read file: %w", err)
}
// For CLI commands, use ui.Error() and return
if err != nil {
ui.Error(fmt.Sprintf("Failed to read: %v", err))
return
}
type TodoItem struct {
ID string `json:"id"`
Content string `json:"content"`
Status string `json:"status"` // "pending", "in_progress", "completed", "cancelled"
Priority string `json:"priority"` // "high", "medium", "low"
Children []TodoItem `json:"children,omitempty"`
}
Each command should have:
Use: command name and argument placeholdersShort: one-line descriptionLong: detailed description with examplesRun or RunE: handler functionArgs, ValidArgsFunction for completionvar myCmd = &cobra.Command{
Use: "mycommand <arg>",
Short: "Brief description",
Long: `Detailed description.
Examples:
nocturnal mycommand example`,
Args: cobra.ExactArgs(1),
Run: runMyCommand,
}
Use the cmd package's output helpers for consistent terminal output:
printSuccess("Operation completed")
printError("Something went wrong")
printWarning("Be careful")
printInfo("FYI")
printDim("Secondary info")
This project uses its own specification management. When working on proposals:
nocturnal agent projectnocturnal agent currentnocturnal agent specsnocturnal spec proposal add my-feature # Create proposal
nocturnal spec proposal activate my-feature # Set as active
# ... implement the feature ...
nocturnal spec proposal complete my-feature # Archive and promote
github.com/spf13/cobra - CLI frameworkgithub.com/charmbracelet/lipgloss - Terminal stylinggithub.com/mark3labs/mcp-go - MCP server protocol*_test.go in the same packagego test -v -run TestFunctionName ./...t.Helper() in test helper functions//go:embed directive in spec.go./spec/spec/third/spec/.nocturnal.jsonfunc runMyCmd(cmd *cobra.Command, args []string) {...}init(): parentCmd.AddCommand(myCmd)registerMyTool(s *server.MCPServer) function in mcp.gomcp.NewTool() and handlerrunMCP(): registerMyTool(s)registerMyPrompt(s *server.MCPServer) function in mcp.gomcp.NewPrompt() and handlerrunMCP(): registerMyPrompt(s)cmd/templates/help/mcp.txt to document the new promptExample:
func registerMyPrompt(s *server.MCPServer) {
prompt := mcp.NewPrompt("my-prompt",
mcp.WithPromptDescription("Brief description of what this prompt does"),
mcp.WithArgument("arg1",
mcp.ArgumentDescription("Description of argument"),
mcp.RequiredArgument(), // Optional
),
)
s.AddPrompt(prompt, func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
promptText := `Instructions for the AI agent...`
return &mcp.GetPromptResult{
Description: "Brief description",
Messages: []mcp.PromptMessage{
{
Role: mcp.RoleUser,
Content: mcp.TextContent{
Type: "text",
Text: promptText,
},
},
},
}, nil
})
}