Skip to content

bretuobay/fyi-notes-cli

Repository files navigation

FYI Notes CLI Parser

A command-line tool that parses plain-text files in the FYI Notes format and transforms them into structured JSON. FYI Notes allows you to embed machine-parsable metadata blocks directly within your notes using @ or # delimiters, bridging human-readable note-taking with structured data extraction.

Features

  • Simple Metadata Syntax: Embed metadata anywhere in your notes using @key: value @ or #key: value #
  • Automatic Extraction: Automatically detects URLs, adds timestamps, and generates descriptions
  • Flexible Output: Output to stdout or file, with optional pretty-printing
  • Validation: Check syntax without processing
  • Query: Extract specific metadata fields
  • Cross-Platform: Runs on Linux, macOS, and Windows
  • Fast: Parses files in milliseconds (<100ms for <100KB files)
  • Well-Tested: >90% test coverage with comprehensive unit and integration tests

Installation

Pre-built Binaries

Download the latest release for your platform from the releases page.

Build from Source

Requirements:

  • Go 1.22.3 or later
# Clone the repository
git clone https://github.com/bretuobay/fyi-notes-cli.git
cd fyi-notes-cli

# Build using Make
make build

# Or build using the shell script
./build.sh

# Or build directly with Go
go build -o fyicli ./cmd/fyicli

Install to System

# Install to $GOPATH/bin
make install

# Or use go install directly from GitHub
go install github.com/bretuobay/fyi-notes-cli/cmd/fyicli@latest

Quick Start

Create a file called notes.fyi:

#fyi
@title: My First Note @
@tags: ["personal", "ideas"] @

This is a simple note with embedded metadata.
Check out https://example.com for more info.

@author: John Doe @

Parse it to JSON:

fyicli parse notes.fyi --pretty

For a complete quick start guide, see QUICKSTART.md.

Output:

{
  "format_version": "1.0",
  "source_file": "notes.fyi",
  "parsed_at": "2026-01-26T00:00:00Z",
  "content": [
    {
      "type": "metadata",
      "key": "title",
      "value": "My First Note"
    },
    {
      "type": "metadata",
      "key": "tags",
      "value": ["personal", "ideas"]
    },
    {
      "type": "text",
      "content": "This is a simple note with embedded metadata.\nCheck out https://example.com for more info."
    },
    {
      "type": "metadata",
      "key": "author",
      "value": "John Doe"
    }
  ],
  "metadata": {
    "title": "My First Note",
    "tags": ["personal", "ideas"],
    "author": "John Doe",
    "date": "2026-01-26",
    "description": "This is a simple note with embedded metadata.\nCheck out https://example.com for more info.",
    "links": ["https://example.com"]
  }
}

File Format

File Recognition

FYI Notes files are recognized by:

  • File extension: .fyi or .notes
  • File declaration: #fyi or #notes on the first non-empty line

Metadata Blocks

Metadata blocks use delimiters (@ or #) to mark boundaries:

Single-line values:

@key: value @
#key: value #

Multi-line values:

@description:
This is a multi-line value.
It can span multiple lines.
@

Array values (JSON syntax):

@tags: ["frontend", "backend", "api"] @

Key Rules

  • Keys must match the pattern [a-zA-Z0-9_-]+
  • Keys are case-sensitive
  • Duplicate keys are automatically merged into arrays

Automatic Metadata

The parser automatically adds:

  • date: Current date in ISO 8601 format (if not provided)
  • description: Generated from all text content (if not provided)
  • links: All URLs found in the document (if any exist)

URLs are detected from:

  • http:// and https:// protocols
  • ftp:// and file:// protocols
  • www. domains (converted to https://)
  • Markdown links [text](url)

Commands

parse

Parse a FYI Notes file and output structured JSON.

fyicli parse [options] <file>

Options:

  • --output <path>: Write output to file instead of stdout
  • --pretty: Pretty-print JSON with indentation
  • --no-auto: Disable automatic metadata extraction

Examples:

# Parse to stdout
fyicli parse notes.fyi

# Parse with pretty printing
fyicli parse notes.fyi --pretty

# Parse to file
fyicli parse notes.fyi --output output.json

# Parse without automatic metadata
fyicli parse notes.fyi --no-auto

Exit Codes:

  • 0: Success
  • 1: Parse error
  • 3: File not found or I/O error

validate

Validate the syntax of a FYI Notes file without producing output.

fyicli validate <file>

Examples:

# Validate a file
fyicli validate notes.fyi

# Check exit code
fyicli validate notes.fyi && echo "Valid" || echo "Invalid"

Exit Codes:

  • 0: Validation successful
  • 2: Validation failed
  • 3: File not found or I/O error

query

Extract specific metadata fields from a FYI Notes file.

fyicli query [options] <file>

Options:

  • --key <name>: Metadata key to extract (required)
  • --format <type>: Output format: json or csv (default: json)

Examples:

# Extract a single field
fyicli query notes.fyi --key title

# Extract an array field as CSV
fyicli query notes.fyi --key tags --format csv

# Extract auto-generated links
fyicli query notes.fyi --key links

Exit Codes:

  • 0: Success (even if key doesn't exist)
  • 1: Parse error
  • 3: File not found or I/O error

version

Show version information.

fyicli version

help

Show help message.

fyicli help
fyicli <command> -h

Examples

See the examples/ directory for sample FYI Notes files demonstrating various features:

  • simple.fyi: Basic metadata and text
  • multi-line.fyi: Multi-line values
  • arrays.fyi: Array values and duplicate keys
  • urls.fyi: Automatic URL extraction
  • edge-cases.fyi: Edge cases and special scenarios

Error Messages

The parser provides clear error messages with line numbers:

Unclosed block:

Parse error: Unclosed metadata block 'description' starting at line 5

Mismatched delimiters:

Parse error: Delimiter mismatch: opened with '@' at line 3, closed with '#' at line 3

Invalid key:

Parse error: Invalid key 'my.key' at line 2 (keys must match [a-zA-Z0-9_-]+)

Value too large:

Parse error: Value for key 'content' exceeds 100 KB limit

Invalid JSON array:

Parse error: Invalid JSON array syntax for key 'tags' at line 4

Troubleshooting

File not recognized as FYI Notes format

Problem: Parser doesn't recognize your file.

Solution: Ensure your file either:

  • Has a .fyi or .notes extension, OR
  • Has #fyi or #notes as the first non-empty line

Delimiter mismatch error

Problem: Delimiter mismatch: opened with '@' at line X, closed with '#' at line Y

Solution: Use matching delimiters. If you open with @, close with @. If you open with #, close with #.

# Wrong
@title: My Note #

# Correct
@title: My Note @

Invalid key error

Problem: Invalid key 'my.key' at line X

Solution: Keys can only contain letters, numbers, underscores, and hyphens. No spaces or special characters.

# Wrong
@my.key: value @
@my key: value @

# Correct
@my_key: value @
@my-key: value @

Unclosed block error

Problem: Unclosed metadata block 'key' starting at line X

Solution: Ensure every metadata block has a closing delimiter.

# Wrong
@description: This is my note

# Correct
@description: This is my note @

Multi-line value not working

Problem: Multi-line value is treated as single line.

Solution: Put a newline immediately after the colon:

# Wrong
@description: Line 1
Line 2
@

# Correct
@description:
Line 1
Line 2
@

JSON array parsing error

Problem: Invalid JSON array syntax for key 'tags'

Solution: Use proper JSON syntax with quoted strings:

# Wrong
@tags: [tag1, tag2] @

# Correct
@tags: ["tag1", "tag2"] @

Library Usage

You can also use the parser as a Go library in your own projects:

package main

import (
    "fmt"
    "github.com/bretuobay/fyi-notes-cli/pkg/parser"
    "github.com/bretuobay/fyi-notes-cli/pkg/extractor"
)

func main() {
    // Parse a file
    content := `@title: My Note @
    Some text content.`
    
    p := parser.NewParser(content)
    doc, err := p.Parse()
    if err != nil {
        panic(err)
    }
    
    // Add automatic metadata
    urlExtractor := extractor.NewURLExtractor()
    urlExtractor.AddLinksField(doc)
    extractor.AddDateField(doc, extractor.SystemClock{})
    extractor.AddDescriptionField(doc)
    
    // Convert to JSON
    jsonData, err := doc.ToJSONPretty()
    if err != nil {
        panic(err)
    }
    
    fmt.Println(string(jsonData))
}

Install as a Library

go get github.com/bretuobay/fyi-notes-cli

Building

Build for Current Platform

make build
# or
./build.sh

The binary will be created as fyicli in the project root.

Build for All Platforms

make cross-platform
# or
./build.sh all

This creates binaries for:

  • Linux (amd64)
  • macOS (amd64, arm64)
  • Windows (amd64)

Binaries are placed in the project root with platform-specific names.

Run Tests

# Run all tests
make test

# Run tests with verbose output
go test -v ./...

# Run specific package tests
go test ./pkg/parser/

Generate Coverage Report

make coverage
# or
go test -cover ./...

Clean Build Artifacts

make clean

Project Structure

fyi-notes-cli/
├── cmd/
│   └── fyicli/          # CLI entry point
│       └── main.go
├── pkg/
│   ├── parser/          # Core parsing logic
│   │   ├── parser.go
│   │   ├── types.go
│   │   └── *_test.go
│   ├── extractor/       # Auto-extraction (URLs, dates, descriptions)
│   │   ├── extractor.go
│   │   └── *_test.go
│   └── printer/         # Pretty printer for round-trip testing
│       ├── printer.go
│       └── *_test.go
├── docs/                # Documentation
│   ├── SPECIFICATION.md
│   ├── PRD.md
│   ├── CONTRIBUTING.md
│   ├── CHANGELOG.md
│   ├── QUICKSTART.md
│   └── DEVELOPMENT.md
├── examples/            # Example FYI Notes files
├── .kiro/
│   └── specs/          # Design specifications
│       └── fyi-notes-parser/
│           ├── requirements.md
│           ├── design.md
│           └── tasks.md
├── Makefile            # Build automation
├── build.sh            # Build script
├── go.mod              # Go module definition
└── README.md           # This file

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for detailed guidelines.

Quick Contribution Guide

  1. All tests pass: make test
  2. Code follows Go conventions: gofmt, go vet
  3. New features include tests
  4. Documentation is updated

Development Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Make your changes
  4. Run tests: make test
  5. Commit your changes: git commit -am 'Add feature'
  6. Push to the branch: git push origin feature-name
  7. Submit a pull request

Reporting Issues

Please report issues on the GitHub issue tracker.

Include:

  • FYI Notes file that causes the issue (if applicable)
  • Expected behavior
  • Actual behavior
  • Error messages
  • Operating system and Go version

License

MIT License - see LICENSE file for details.

Links

Documentation

For complete documentation, see the docs/ directory:

About

A new simple file format specification for taking notes, parsable to JSON making it easy to parse and store

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors