Skip to content

About

Tiny ruby client for the Fresh Jots API

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

freshjots — Ruby

Tiny Ruby client for the Fresh Jots API. One file, no runtime dependencies (uses net/http from stdlib).

Install

# Gemfile
gem "freshjots"
bundle install

Or globally:

gem install freshjots

Use

require "freshjots"

# Reads FRESHJOTS_TOKEN from the environment by default.
client = Freshjots::Client.new

# Append text to a note (creates it if missing).
client.append("cron-jobs-prod", "backup ok #{Time.now.utc.iso8601}")

# Read a note's body.
puts client.note("cron-jobs-prod")[:plain_body]

# List your notes (most recent activity first). Sort and filter with options:
client.notes(sort: "created", folder_id: 3, limit: 20).each do |note|
  puts "#{note[:id]}\t#{note[:filename]}\t#{note[:title]}"
end

# Create a note. The API derives the filename from the title — for a
# note addressable by an exact filename, use append instead.
created = client.create(title: "Research 2026 Q2", body: "Initial outline.")
puts created[:filename] # server-derived stream name

# Update a note's fields (only the keys you pass change). By id or by filename:
client.update(42, title: "Q2 research", body: "Revised outline.")
client.set("cron-jobs-prod", folder: "Ops", deadline: 26)   # metadata only, no body needed

# Create many notes in one atomic batch (up to 50 — all land or none do).
client.bulk([{ title: "a", plain_body: "1" }, { title: "b", plain_body: "2" }])

# Organize: move into a folder (by id or name), delete (by id or filename).
client.move("cron-jobs-prod", folder: "Ops")
client.delete("old-note")

# Folders: list, read one, create, rename, delete (its notes move to the built-in default folder).
client.folders.each { |f| puts "#{f[:id]}\t#{f[:name]}" }
ops = client.create_folder("Ops")
client.rename_folder(ops[:id], "Operations")
client.delete_folder(ops[:id])

Client methods: notes(sort:, folder_id:, limit:, offset:), note(filename), note_by_id(id), create(title:, body:, client_encrypted:), append(filename, text, client_encrypted:), update(id, **fields), set(filename, **fields), bulk(notes), delete(id_or_filename), move(id_or_filename, folder:), folders, folder(id), create_folder(name), rename_folder(id, name), and delete_folder(id). Client-side crypto: Freshjots.encrypt(text, passphrase) / Freshjots.decrypt(token, passphrase) (see Encryption). note/note_by_id/create/update/set and the single-folder methods return the hash directly (no { note: … } / { folder: … } wrapper); notes and folders return arrays, and bulk returns { created: [...] }. For update/set, the fields are title:, body:, folder: (id or name — root: true un-folders), deadline:, alert_email:, webhook_url:, webhook_secret:; changing title: rewrites the body as a unit, so pass body: too. For notes, sort is created|updated|appended and folder_id may be a folder id or "none" (un-foldered only).

Encryption

Keep notes the server can't read: encrypt locally with your own passphrase, store the ciphertext, decrypt locally on read. Built in on Ruby's stdlib openssl (no gem dependencies), and interoperable with the JS and Python clients.

require "freshjots"

client = Freshjots::Client.new
pw = ENV.fetch("FRESHJOTS_PASSPHRASE")

# Store an encrypted note: encrypt the body, flag it client_encrypted.
client.create(title: "Recovery codes", body: Freshjots.encrypt("1234-5678", pw), client_encrypted: true)

# Read it back and decrypt locally.
puts Freshjots.decrypt(client.note("recovery-codes")[:plain_body], pw)

The format is fj1 (AES-256-CBC + HMAC-SHA256, PBKDF2-HMAC-SHA256), interoperable with the JS, Python, MCP, and shell (brew) clients. You hold the only key — Fresh Jots never receives it and cannot recover the note if you lose it, so back the passphrase up somewhere safe. Encryption is per-note and personal-only (not team notes); the title and metadata stay in the clear, so keep secrets out of the title. Freshjots.decrypt raises Freshjots::EncryptionError on a wrong passphrase. See https://freshjots.com/encrypted-notes.

Errors

Any non-2xx response raises Freshjots::ApiError with status, code, message, and (when present) details from the API's stable error envelope:

begin
  client.append("huge", "x" * 5_000_000)
rescue Freshjots::ApiError => e
  puts "#{e.status} #{e.code}: #{e.message}"
  # 413 content_too_large: body exceeds the per-note 3 MB cap
end

Stable error codes: unauthenticated, forbidden, not_found, validation_failed, cap_exceeded, storage_cap_exceeded, content_too_large, content_type_mismatch, rate_limited. Full list: https://freshjots.com/docs.

Auth

Mint a token at https://freshjots.com/settings/api_tokens (Dev or Team tier required). Set it once, persisted for every new shell (macOS defaults to zsh; use ~/.bashrc on bash):

echo 'export FRESHJOTS_TOKEN=<your-token>' >> ~/.zshrc && source ~/.zshrc

Or pass explicitly:

Freshjots::Client.new(token: "mn_…")

License

MIT.

About

Tiny ruby client for the Fresh Jots API

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages