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.
- 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
Download the latest release for your platform from the releases page.
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 $GOPATH/bin
make install
# Or use go install directly from GitHub
go install github.com/bretuobay/fyi-notes-cli/cmd/fyicli@latestCreate 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 --prettyFor 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"]
}
}FYI Notes files are recognized by:
- File extension:
.fyior.notes - File declaration:
#fyior#noteson the first non-empty line
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"] @
- Keys must match the pattern
[a-zA-Z0-9_-]+ - Keys are case-sensitive
- Duplicate keys are automatically merged into arrays
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://andhttps://protocolsftp://andfile://protocolswww.domains (converted tohttps://)- Markdown links
[text](url)
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-autoExit Codes:
0: Success1: Parse error3: File not found or I/O error
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 successful2: Validation failed3: File not found or I/O error
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:jsonorcsv(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 linksExit Codes:
0: Success (even if key doesn't exist)1: Parse error3: File not found or I/O error
Show version information.
fyicli versionShow help message.
fyicli help
fyicli <command> -hSee the examples/ directory for sample FYI Notes files demonstrating various features:
simple.fyi: Basic metadata and textmulti-line.fyi: Multi-line valuesarrays.fyi: Array values and duplicate keysurls.fyi: Automatic URL extractionedge-cases.fyi: Edge cases and special scenarios
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
Problem: Parser doesn't recognize your file.
Solution: Ensure your file either:
- Has a
.fyior.notesextension, OR - Has
#fyior#notesas the first non-empty line
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 @
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 @
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 @
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
@
Problem: Invalid JSON array syntax for key 'tags'
Solution: Use proper JSON syntax with quoted strings:
# Wrong
@tags: [tag1, tag2] @
# Correct
@tags: ["tag1", "tag2"] @
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))
}go get github.com/bretuobay/fyi-notes-climake build
# or
./build.shThe binary will be created as fyicli in the project root.
make cross-platform
# or
./build.sh allThis creates binaries for:
- Linux (amd64)
- macOS (amd64, arm64)
- Windows (amd64)
Binaries are placed in the project root with platform-specific names.
# Run all tests
make test
# Run tests with verbose output
go test -v ./...
# Run specific package tests
go test ./pkg/parser/make coverage
# or
go test -cover ./...make cleanfyi-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
Contributions are welcome! Please see CONTRIBUTING.md for detailed guidelines.
- All tests pass:
make test - Code follows Go conventions:
gofmt,go vet - New features include tests
- Documentation is updated
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes
- Run tests:
make test - Commit your changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
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
MIT License - see LICENSE file for details.
- GitHub Repository: https://github.com/bretuobay/fyi-notes-cli
- Issue Tracker: https://github.com/bretuobay/fyi-notes-cli/issues
- Releases: https://github.com/bretuobay/fyi-notes-cli/releases
For complete documentation, see the docs/ directory:
- SPECIFICATION.md - File format specification
- PRD.md - Product requirements document
- CONTRIBUTING.md - Contributing guidelines
- CHANGELOG.md - Version history
- QUICKSTART.md - Quick start guide
- DEVELOPMENT.md - Development best practices (Go-specific)