sncli

package module
v0.0.0-...-3099bdf Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2025 License: AGPL-3.0 Imports: 28 Imported by: 0

README

📝 sn-cli

A modern command-line interface for Standard Notes

Build Status Go Report Card

✨ Features

  • 📋 Notes & Tasks: Create, edit, and manage notes and checklists
  • 🏷️ Tags: Organize content with flexible tagging
  • 📊 Statistics: Detailed analytics about your notes and usage
  • 🔐 Secure Sessions: Keychain integration for macOS and Linux
  • ⚡ Fast Sync: Efficient synchronization with Standard Notes servers
  • 🔄 Multi-Platform: Windows, macOS, and Linux support

🚀 Quick Start

Installation

Download the latest release:

# macOS/Linux
curl -L https://github.com/jonhadfield/sn-cli/releases/latest/download/sncli_$(uname -s)_$(uname -m) -o sn
chmod +x sn && sudo mv sn /usr/local/bin/

# Or via direct download
# Visit: https://github.com/jonhadfield/sn-cli/releases
First Run
# See all available commands
sn --help

# Add a note
sn add note --title "My First Note" --text "Hello, Standard Notes!"

# List your notes
sn get notes

# View statistics
sn stats

📋 Commands

Command Description
add Add notes, tags, or tasks
delete Delete items by title or UUID
edit Edit existing notes
get Retrieve notes, tags, or tasks
tag Manage tags and tagging
task Manage checklists and advanced checklists
stats Display detailed statistics
session Manage stored sessions
register Register a new Standard Notes account
resync Refresh local cache
wipe Delete all notes and tags

Note: Export and import are temporarily disabled due to recent Standard Notes API changes

🔐 Authentication

Environment Variables
export SN_EMAIL="your-email@example.com"
export SN_PASSWORD="your-password"
export SN_SERVER="https://api.standardnotes.com"  # Optional for self-hosted

Store encrypted sessions in your system keychain:

# Add session (supports 2FA)
sn session --add

# Add encrypted session
sn session --add --session-key

# Use session automatically
export SN_USE_SESSION=true
# or
sn --use-session get notes

🆕 Recent Updates

Version 0.3.5 (2024-01-08)
  • 🐛 Fixed: Conflict warning handling
  • Added: Helper tests
  • 🔧 Improved: Code simplification
Version 0.3.4 (2024-01-07)
  • 🐛 Fixed: Command completion and updated instructions

View full changelog →

💡 Examples

# Create a note with tags
sn add note --title "Meeting Notes" --text "Important discussion points" --tag work,meetings

# Find notes by tag
sn get notes --tag work

# Create a checklist
sn add task --title "Todo List" --text "- Buy groceries\n- Call dentist\n- Finish project"

# View your note statistics
sn stats

# Edit a note
sn edit note --title "Meeting Notes" --text "Updated content"

⚙️ Advanced Configuration

Bash Completion
macOS (Homebrew)
brew install bash-completion
echo '[ -f /usr/local/etc/bash_completion ] && . /usr/local/etc/bash_completion' >> ~/.bash_profile
Install completion script
# macOS
cp bash_autocomplete /usr/local/etc/bash_completion.d/sn
echo "source /usr/local/etc/bash_completion.d/sn" >> ~/.bashrc

# Linux
cp bash_autocomplete /etc/bash_completion.d/sn
echo "source /etc/bash_completion.d/sn" >> ~/.bashrc
Self-Hosted Servers
export SN_SERVER="https://your-standardnotes-server.com"

🔧 Development

# Build from source
git clone https://github.com/jonhadfield/sn-cli.git
cd sn-cli
make build

# Run tests
make test

# View all make targets
make help

⚠️ Known Issues

  • New accounts registered via sn-cli require initial login through the official web/desktop app to initialize encryption keys

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


Documentation

Index

Constants

View Source
const (
	SNServerURL       = "https://api.standardnotes.com"
	SNPageSize        = 600
	SNAppName         = "sn-cli"
	MinPasswordLength = 8
)

Variables

This section is empty.

Functions

func CommaSplit

func CommaSplit(i string) []string

func DecryptString

func DecryptString(input DecryptStringInput) (string, error)

func ItemKeysHealthcheck

func ItemKeysHealthcheck(input ItemsKeysHealthcheckInput) error

func OutputSession

func OutputSession(input OutputSessionInput) error

func RemoveDeleted

func RemoveDeleted(in items.Items) items.Items

func Resync

func Resync(s *cache.Session, cacheDBDir, appName string) error

func StringInSlice

func StringInSlice(inStr string, inSlice []string, matchCase bool) bool

func Sync

func Sync(si cache.SyncInput, useStdErr bool) (cache.SyncOutput, error)

Types

type AddAdvancedChecklistTaskInput

type AddAdvancedChecklistTaskInput struct {
	Session  *cache.Session
	Debug    bool
	UUID     string
	Title    string
	Group    string
	Tasklist string
}

func (*AddAdvancedChecklistTaskInput) Run

type AddNoteInput

type AddNoteInput struct {
	Session  *cache.Session
	Title    string
	Text     string
	FilePath string
	Tags     []string
	Replace  bool
	Debug    bool
}

func (*AddNoteInput) Run

func (i *AddNoteInput) Run() error

type AddTagsInput

type AddTagsInput struct {
	Session    *cache.Session
	Tags       []string
	Parent     string
	ParentUUID string
	Debug      bool
	Replace    bool
}

func (*AddTagsInput) Run

func (i *AddTagsInput) Run() (AddTagsOutput, error)

type AddTagsOutput

type AddTagsOutput struct {
	Added, Existing []string
}

type AddTaskInput

type AddTaskInput struct {
	Session  *cache.Session
	Debug    bool
	Title    string
	UUID     string
	Tasklist string
}

func (*AddTaskInput) Run

func (ci *AddTaskInput) Run() error

type AdvancedChecklist

type AdvancedChecklist struct {
	UUID            string                   `json:"-"`
	Duplicates      []AdvancedChecklist      `json:"-"`
	Title           string                   `json:"-"`
	SchemaVersion   string                   `json:"schemaVersion"`
	Groups          []AdvancedChecklistGroup `json:"groups"`
	DefaultSections []DefaultSection         `json:"defaultSections"`
	UpdatedAt       time.Time                `json:"updatedAt"`
	Trashed         bool                     `json:"trashed"`
}

func (*AdvancedChecklist) Sort

func (c *AdvancedChecklist) Sort()

type AdvancedChecklistGroup

type AdvancedChecklistGroup struct {
	Name       string                     `json:"name"`
	LastActive time.Time                  `json:"lastActive"`
	Sections   []AdvancedChecklistSection `json:"sections"`
	Tasks      AdvancedChecklistTasks     `json:"tasks"`
	Collapsed  bool                       `json:"collapsed"`
}

type AdvancedChecklistSection

type AdvancedChecklistSection struct {
	Id        string `json:"id"`
	Name      string `json:"name"`
	Collapsed bool   `json:"collapsed"`
}

type AdvancedChecklistTask

type AdvancedChecklistTask struct {
	Id          string    `json:"id"`
	Description string    `json:"description"`
	Completed   bool      `json:"completed"`
	CreatedAt   time.Time `json:"createdAt"`
	UpdatedAt   time.Time `json:"updatedAt"`
}

type AdvancedChecklistTasks

type AdvancedChecklistTasks []AdvancedChecklistTask

func (*AdvancedChecklistTasks) Sort

func (t *AdvancedChecklistTasks) Sort()

type AppDataContentJSON

type AppDataContentJSON struct {
	OrgStandardNotesSN           OrgStandardNotesSNDetailJSON             `json:"org.standardnotes.sn"`
	OrgStandardNotesSNComponents items.OrgStandardNotesSNComponentsDetail `json:"org.standardnotes.sn.components,omitempty"`
}

type AppDataContentYAML

type AppDataContentYAML struct {
	OrgStandardNotesSN           OrgStandardNotesSNDetailYAML             `yaml:"org.standardnotes.sn"`
	OrgStandardNotesSNComponents items.OrgStandardNotesSNComponentsDetail `yaml:"org.standardnotes.sn.components,omitempty"`
}

type CompleteAdvancedTaskInput

type CompleteAdvancedTaskInput struct {
	Session  *cache.Session
	Debug    bool
	Title    string
	Group    string
	Tasklist string
	UUID     string
}

func (*CompleteAdvancedTaskInput) Run

func (ci *CompleteAdvancedTaskInput) Run() error

type CompleteTaskInput

type CompleteTaskInput struct {
	Session  *cache.Session
	Debug    bool
	Title    string
	Tasklist string
	UUID     string
}

func (*CompleteTaskInput) Run

func (ci *CompleteTaskInput) Run() error

type CreateItemsKeyInput

type CreateItemsKeyInput struct {
	Debug     bool
	MasterKey string
}

type DecryptStringInput

type DecryptStringInput struct {
	Session   session.Session
	In        string
	UseStdOut bool
	Key       string
}

type DefaultSection

type DefaultSection struct {
	Id   string `json:"id"`
	Name string `json:"name"`
}

type DeleteAdvancedChecklistTaskInput

type DeleteAdvancedChecklistTaskInput struct {
	Session   *cache.Session
	Debug     bool
	Title     string
	Group     string
	Checklist string
	UUID      string
}

func (*DeleteAdvancedChecklistTaskInput) Run

type DeleteItemConfig

type DeleteItemConfig struct {
	Session    *cache.Session
	NoteTitles []string
	NoteText   string
	ItemsUUIDs []string
	Regex      bool
	Debug      bool
}

func (*DeleteItemConfig) Run

func (i *DeleteItemConfig) Run() (int, error)

type DeleteNoteConfig

type DeleteNoteConfig struct {
	Session    *cache.Session
	NoteTitles []string
	NoteText   string
	NoteUUIDs  []string
	Regex      bool
	Debug      bool
}

func (*DeleteNoteConfig) Run

func (i *DeleteNoteConfig) Run() (int, error)

type DeleteTagConfig

type DeleteTagConfig struct {
	Session   *cache.Session
	Email     string
	TagTitles []string
	TagUUIDs  []string
	Regex     bool
	Debug     bool
}

func (*DeleteTagConfig) Run

func (i *DeleteTagConfig) Run() (int, error)

type DeleteTaskInput

type DeleteTaskInput struct {
	Session  *cache.Session
	Debug    bool
	Title    string
	Tasklist string
	UUID     string
}

func (*DeleteTaskInput) Run

func (ci *DeleteTaskInput) Run() error

type EncryptedItemExport

type EncryptedItemExport struct {
	UUID        string `json:"uuid"`
	ItemsKeyID  string `json:"items_key_id,omitempty"`
	Content     string `json:"content"`
	ContentType string `json:"content_type"`
	// Deleted            bool    `json:"deleted"`
	EncItemKey         string  `json:"enc_item_key"`
	CreatedAt          string  `json:"created_at"`
	UpdatedAt          string  `json:"updated_at"`
	CreatedAtTimestamp int64   `json:"created_at_timestamp"`
	UpdatedAtTimestamp int64   `json:"updated_at_timestamp"`
	DuplicateOf        *string `json:"duplicate_of"`
}

type EncryptedItemsFile

type EncryptedItemsFile struct {
	Items items.EncryptedItems `json:"items"`
}

type ExportConfig

type ExportConfig struct {
	Session   *cache.Session
	Decrypted bool
	File      string
	UseStdOut bool
}

type GetItemsConfig

type GetItemsConfig struct {
	Session *cache.Session
	Filters items.ItemFilters
	Output  string
	Debug   bool
}

func (*GetItemsConfig) Run

func (i *GetItemsConfig) Run() (items.Items, error)

type GetNoteConfig

type GetNoteConfig struct {
	Session    *cache.Session
	Filters    items.ItemFilters
	NoteTitles []string
	TagTitles  []string
	TagUUIDs   []string
	PageSize   int
	BatchSize  int
	Debug      bool
}

func (*GetNoteConfig) Run

func (i *GetNoteConfig) Run() (items.Items, error)

type GetSettingsConfig

type GetSettingsConfig struct {
	Session *cache.Session
	Filters items.ItemFilters
	Output  string
	Debug   bool
}

func (*GetSettingsConfig) Run

func (i *GetSettingsConfig) Run() (items.Items, error)

type GetTagConfig

type GetTagConfig struct {
	Session *cache.Session
	Filters items.ItemFilters
	Output  string
	Debug   bool
}

func (*GetTagConfig) Run

func (i *GetTagConfig) Run() (items.Items, error)

type ImportConfig

type ImportConfig struct {
	Session   *cache.Session
	File      string
	Format    string
	UseStdOut bool
	Debug     bool
}

type ItemOrphanedRefs

type ItemOrphanedRefs struct {
	ContentType  string
	Item         items.Item
	OrphanedRefs []string
}

type ItemReferenceJSON

type ItemReferenceJSON struct {
	UUID          string `json:"uuid"`
	ContentType   string `json:"content_type"`
	ReferenceType string `json:"reference_type,omitempty"`
}

func ItemRefsToJSON

func ItemRefsToJSON(irs []items.ItemReference) []ItemReferenceJSON

type ItemReferenceYAML

type ItemReferenceYAML struct {
	UUID          string `yaml:"uuid"`
	ContentType   string `yaml:"content_type"`
	ReferenceType string `yaml:"reference_type,omitempty"`
}

func ItemRefsToYaml

func ItemRefsToYaml(irs []items.ItemReference) []ItemReferenceYAML

type ItemsKeysHealthcheckInput

type ItemsKeysHealthcheckInput struct {
	Session       session.Session
	UseStdOut     bool
	DeleteInvalid bool
}

type ListChecklistsInput

type ListChecklistsInput struct {
	Session *cache.Session
	Debug   bool
}

type ListTasklistsInput

type ListTasklistsInput struct {
	Session  *cache.Session
	Ordering string
	Debug    bool
}

func (*ListTasklistsInput) Run

func (ci *ListTasklistsInput) Run() error

type NoteContentJSON

type NoteContentJSON struct {
	Title            string              `json:"title"`
	Text             string              `json:"text"`
	ItemReferences   []ItemReferenceJSON `json:"references"`
	AppData          AppDataContentJSON  `json:"appData"`
	EditorIdentifier string              `json:"editorIdentifier"`
	PreviewPlain     string              `json:"preview_plain"`
	PreviewHtml      string              `json:"preview_html"`
	Spellcheck       bool                `json:"spellcheck"`
	Trashed          *bool               `json:"trashed,omitempty"`
}

type NoteContentYAML

type NoteContentYAML struct {
	Title            string              `yaml:"title"`
	Text             string              `json:"text"`
	ItemReferences   []ItemReferenceYAML `yaml:"references"`
	AppData          AppDataContentYAML  `yaml:"appData"`
	EditorIdentifier string              `yaml:"editorIdentifier"`
	PreviewPlain     string              `yaml:"preview_plain"`
	PreviewHtml      string              `yaml:"preview_html"`
	Spellcheck       bool                `yaml:"spellcheck"`
	Trashed          *bool               `yaml:"trashed,omitempty"`
}

type NoteJSON

type NoteJSON struct {
	UUID        string          `json:"uuid"`
	Content     NoteContentJSON `json:"content"`
	ContentType string          `json:"content_type"`
	CreatedAt   string          `json:"created_at"`
	UpdatedAt   string          `json:"updated_at"`
}

type NoteYAML

type NoteYAML struct {
	UUID        string          `yaml:"uuid"`
	Content     NoteContentYAML `yaml:"content"`
	ContentType string          `yaml:"content_type"`
	CreatedAt   string          `yaml:"created_at"`
	UpdatedAt   string          `yaml:"updated_at"`
}

type OrgStandardNotesSNComponentsDetailJSON

type OrgStandardNotesSNComponentsDetailJSON map[string]interface{}

type OrgStandardNotesSNDetailJSON

type OrgStandardNotesSNDetailJSON struct {
	ClientUpdatedAt    string `json:"client_updated_at"`
	PrefersPlainEditor bool   `json:"prefersPlainEditor"`
	Pinned             bool   `json:"pinned"`
}

type OrgStandardNotesSNDetailYAML

type OrgStandardNotesSNDetailYAML struct {
	ClientUpdatedAt string `yaml:"client_updated_at"`
}

type OutputSessionInput

type OutputSessionInput struct {
	Session         session.Session
	In              string
	UseStdOut       bool
	OutputMasterKey bool
}

type RegisterConfig

type RegisterConfig struct {
	Email     string
	Password  string
	APIServer string
	Debug     bool
}

func (*RegisterConfig) Run

func (i *RegisterConfig) Run() error

type ReopenAdvancedTaskInput

type ReopenAdvancedTaskInput struct {
	Session  *cache.Session
	Debug    bool
	UUID     string
	Title    string
	Group    string
	Tasklist string
}

func (*ReopenAdvancedTaskInput) Run

func (ci *ReopenAdvancedTaskInput) Run() error

type ReopenTaskInput

type ReopenTaskInput struct {
	Session  *cache.Session
	Debug    bool
	UUID     string
	Title    string
	Tasklist string
}

func (*ReopenTaskInput) Run

func (ci *ReopenTaskInput) Run() error

type SettingContentJSON

type SettingContentJSON struct {
	Title          string              `json:"title"`
	ItemReferences []ItemReferenceJSON `json:"references"`
	AppData        AppDataContentJSON  `json:"appData"`
}

type SettingContentYAML

type SettingContentYAML struct {
	Title          string              `yaml:"title"`
	ItemReferences []ItemReferenceYAML `yaml:"references"`
	AppData        AppDataContentYAML  `yaml:"appData"`
}

type SettingJSON

type SettingJSON struct {
	UUID        string             `json:"uuid"`
	Content     SettingContentJSON `json:"content"`
	ContentType string             `json:"content_type"`
	CreatedAt   string             `json:"created_at"`
	UpdatedAt   string             `json:"updated_at"`
}

type SettingYAML

type SettingYAML struct {
	UUID        string             `yaml:"uuid"`
	Content     SettingContentYAML `yaml:"content"`
	ContentType string             `yaml:"content_type"`
	CreatedAt   string             `yaml:"created_at"`
	UpdatedAt   string             `yaml:"updated_at"`
}

type ShowChecklistInput

type ShowChecklistInput struct {
	Session *cache.Session
	Title   string
	UUID    string
	Debug   bool
}

type ShowTasklistInput

type ShowTasklistInput struct {
	Session       *cache.Session
	Debug         bool
	Group         string
	Title         string
	UUID          string
	ShowCompleted bool
	Ordering      string
}

func (*ShowTasklistInput) Run

func (ci *ShowTasklistInput) Run() error

type StatsConfig

type StatsConfig struct {
	Session cache.Session
}

func (*StatsConfig) GetData

func (i *StatsConfig) GetData() (StatsData, error)

func (*StatsConfig) Run

func (i *StatsConfig) Run() error

type StatsData

type StatsData struct {
	CoreTypeCounter   typeCounter
	OtherTypeCounter  typeCounter
	LargestNotes      []*items.Note
	ItemsOrphanedRefs []ItemOrphanedRefs
	LastUpdatedNote   *items.Note
	NewestNote        *items.Note
	OldestNote        *items.Note
	DuplicateNotes    []*items.Note
}

type TagContentJSON

type TagContentJSON struct {
	Title          string              `json:"title"`
	ItemReferences []ItemReferenceJSON `json:"references"`
	AppData        AppDataContentJSON  `json:"appData"`
}

type TagContentYAML

type TagContentYAML struct {
	Title          string              `yaml:"title"`
	ItemReferences []ItemReferenceYAML `yaml:"references"`
	AppData        AppDataContentYAML  `yaml:"appData"`
}

type TagItemsConfig

type TagItemsConfig struct {
	Session    *cache.Session
	FindTitle  string
	FindText   string
	FindTag    string
	NewTags    []string
	Replace    bool
	IgnoreCase bool
	Debug      bool
}

func (*TagItemsConfig) Run

func (i *TagItemsConfig) Run() error

type TagJSON

type TagJSON struct {
	UUID        string         `json:"uuid"`
	Content     TagContentJSON `json:"content"`
	ContentType string         `json:"content_type"`
	CreatedAt   string         `json:"created_at"`
	UpdatedAt   string         `json:"updated_at"`
}

type TagYAML

type TagYAML struct {
	UUID        string         `yaml:"uuid"`
	Content     TagContentYAML `yaml:"content"`
	ContentType string         `yaml:"content_type"`
	CreatedAt   string         `yaml:"created_at"`
	UpdatedAt   string         `yaml:"updated_at"`
}

type TestDataCreateNotesConfig

type TestDataCreateNotesConfig struct {
	Session  cache.Session
	NumNotes int
	NumParas int
	Debug    bool
}

func (*TestDataCreateNotesConfig) Run

type TestDataCreateTagsConfig

type TestDataCreateTagsConfig struct {
	Session session.Session
	NumTags int64
	Debug   bool
}

func (*TestDataCreateTagsConfig) Run

type WipeConfig

type WipeConfig struct {
	Session    *cache.Session
	UseStdOut  bool
	Debug      bool
	Everything bool
}

func (*WipeConfig) Run

func (i *WipeConfig) Run() (int, error)

Directories

Path Synopsis
cmd
sncli command

Jump to

Keyboard shortcuts

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