{"id":34888395,"url":"https://github.com/aretw0/loam","last_synced_at":"2026-02-17T10:40:53.737Z","repository":{"id":328075706,"uuid":"1111078767","full_name":"aretw0/loam","owner":"aretw0","description":"An Embedded Reactive \u0026 Transactional Engine for Content \u0026 Metadata.","archived":false,"fork":false,"pushed_at":"2026-02-14T07:09:35.000Z","size":491,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-14T15:35:02.724Z","etag":null,"topics":["cli","content-management","database","devops","digital-garden","embedded-database","event-driven","file-watcher","git","gitops","golang","headless-cms","json","knowledge-management","local-first","markdown","pkm","reactive","static-site-generator","yaml"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aretw0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-06T08:17:26.000Z","updated_at":"2026-02-14T07:09:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aretw0/loam","commit_stats":null,"previous_names":["aretw0/loam"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/aretw0/loam","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aretw0%2Floam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aretw0%2Floam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aretw0%2Floam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aretw0%2Floam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aretw0","download_url":"https://codeload.github.com/aretw0/loam/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aretw0%2Floam/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29457937,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T21:29:27.764Z","status":"ssl_error","status_checked_at":"2026-02-14T21:28:11.111Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","content-management","database","devops","digital-garden","embedded-database","event-driven","file-watcher","git","gitops","golang","headless-cms","json","knowledge-management","local-first","markdown","pkm","reactive","static-site-generator","yaml"],"created_at":"2025-12-26T04:21:47.788Z","updated_at":"2026-02-17T10:40:53.723Z","avatar_url":"https://github.com/aretw0.png","language":"Go","readme":"# Loam 🌱\n\n\u003e An Embedded Reactive \u0026 Transactional Engine for Content \u0026 Metadata.\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/aretw0/loam)](https://goreportcard.com/report/github.com/aretw0/loam)\n[![Go Doc](https://godoc.org/github.com/aretw0/loam?status.svg)](https://godoc.org/github.com/aretw0/loam)\n[![License](https://img.shields.io/github/license/aretw0/loam.svg)](LICENSE.txt)\n[![Release](https://img.shields.io/github/release/aretw0/loam.svg?branch=main)](https://github.com/aretw0/loam/releases)\n\n**Loam** é uma engine embutida de documentos desenhada para persistência transacional de conteúdo e metadados.\n\nPor padrão, utiliza o **Sistema de Arquivos + Git** como banco de dados (`.md`, `.yaml`, `.json`, `.csv`), oferecendo controle de versão nativo e legibilidade humana. Sua arquitetura é desacoplada, permitindo a evolução para diferentes backends sem alterar a lógica da aplicação.\n\nÉ ideal para **toolmakers** que constroem:\n\n- **Assistentes de PKM** (Obsidian, Logseq) - *Storage layer apenas*.\n- **Gerenciadores de Configuração** (GitOps, Dotfiles).\n- **Pipelines de Dados Locais** (ETL de CSV/JSON).\n- **Geradores de Sites Estáticos** (Hugo, Jekyll).\n\n## 🗺️ Navegação\n\n- [🤔 Por que Loam?](#why-loam)\n- [📄 Arquivos Suportados](#files)\n- [🚀 Instalação](#install)\n- [🛠️ CLI: Uso Básico](#cli-usage)\n- [📦 Library: Uso em Go](#lib-usage)\n- [📂 Exemplos e Receitas](#examples)\n- [📚 Documentação Técnica](#tech-docs)\n  - [Visão do Produto](docs/PRODUCT.md)\n  - [Arquitetura Técnica](docs/TECHNICAL.md)\n  - [Roadmap \u0026 Planning](docs/PLANNING.md)\n\n## 🤔 Por que Loam? \u003ca name=\"why-loam\"\u003e\u003c/a\u003e\n\n- **Local-First**: Seus dados são arquivos de texto simples. Você mantém controle total e soberania sem depender da engine para acessá-los.\n- **Histórico Nativo**: Todo `Save` gera um rastro auditável no Git. Gerencie versões e correções com a mesma segurança de um repositório de código.\n- **Integridade**: Transações em lote e file-locking garantem que automações e scripts nunca corrompam o estado do cofre.\n- **Reatividade**: Reaja a mudanças externas em tempo real, integrando perfeitamente fluxos locais com sua aplicação.\n\n## 📄 Arquivos Suportados (Smart Persistence) \u003ca name=\"files\"\u003e\u003c/a\u003e\n\nO **Adapter padrão (FS)** detecta automaticamente o formato do arquivo baseado na extensão do ID, suportando leitura e **escrita raw (`--raw`)**:\n\n- **Markdown (`.md`)**: Padrão. Conteúdo + Frontmatter YAML.\n- **JSON (`.json`)**: Serializa como objeto JSON puro. Campo `content` é opcional.\n- **YAML (`.yaml`)**: Serializa como objeto YAML puro. Campo `content` é opcional.\n- **CSV (`.csv`)**: Serializa como linha de valores. Suporta coleções com múltiplos documentos.\n\n\u003e **Smart Retrieval**: Na leitura (`Get`), se o ID não tiver extensão (ex: `dados`), o Loam procura automaticamente por `dados.md`, `dados.json`, etc., respeitando a existência do arquivo.\n\n## 🚀 Instalação \u003ca name=\"install\"\u003e\u003c/a\u003e\n\n### Via Go Install (Recomendado)\n\n```bash\ngo install github.com/aretw0/loam/cmd/loam@latest\n```\n\n### Via Release\n\nBaixe os binários pré-compilados na página de [Releases](https://github.com/aretw0/loam/releases).\n\n### Compilando do Fonte (Build)\n\nPara desenvolvedores, utilizamos `make` para simplificar o processo:\n\n```bash\n# Build para sua plataforma atual\nmake build\n\n# Cross-compilation (Linux, Windows, Mac)\nmake cross-build\n\n# Instalar localmente\nmake install\n```\n\n### Executando Testes\n\nPara rodar a suíte de testes (excluindo testes de stress que podem ser lentos no Windows):\n\n```bash\n# Windows (PowerShell)\ngo test -v ./pkg/... ./cmd/... ./internal/... ./tests/e2e ./tests/reactivity ./tests/typed\n\n# Linux/Mac (via Makefile)\nmake test-fast\n```\n\n## 🛠️ CLI: Uso Básico \u003ca name=\"cli-usage\"\u003e\u003c/a\u003e\n\nO Loam CLI funciona como um \"Gerenciador de Conteúdo\", abstraindo a persistência.\n\n### Inicializar\n\nInicia um cofre Loam. Por padrão usa o adapter de sistema de arquivos (FS + Git).\n\n```bash\nloam init\n# Ou explicitamente:\nloam init --adapter fs\n```\n\n### Criar/Editar Documento\n\nSalva conteúdo e registra a razão da mudança (Commits no caso do Git).\n\n```bash\n# Modo Simples (apenas mensagem)\nloam write -id daily/2025-12-06 -content \"Hoje foi um dia produtivo.\" -m \"log diário\"\n\n# Modo Semântico (Type, Scope, Body)\nloam write -id feature/nova-ideia -content \"...\" --type feat --scope ideias -m \"adiciona rascunho\"\n\n# Modo Imperativo (--set)\n# Define metadados individuais sem precisar de JSON\nloam write --id docs/readme.md --content \"Texto\" --set title=\"Novo Readme\" --set status=draft\n\n# Modo Declarativo (--raw)\n# Envie o documento inteiro via pipe. O Loam detecta Frontmatter/JSON/CSV.\necho '{\"title\":\"Logs\", \"content\":\"...\"}' | loam write --id logs/1.json --raw\n```\n\n\u003e [!NOTE]\n\u003e No modo `--raw`, se o ID não possuir extensão (ex: `--id nota`), a CLI assumirá `.md` por padrão para tentar parsear o conteúdo. Se estiver enviando JSON ou CSV sem extensão no ID, o parse falhará.\n\n### Sincronizar (Sync)\n\nSincroniza o cofre com o remoto configurado (se o adapter suportar).\n\n```bash\nloam sync\n```\n\n### Outros Comandos\n\n- **Ler**: `loam read -id daily/2025-12-06`\n- **Listar**: `loam list`\n- **Deletar**: `loam delete -id daily/2025-12-06`\n\n---\n\n## 📦 Library: Uso em Go \u003ca name=\"lib-usage\"\u003e\u003c/a\u003e\n\nVocê pode embutir o Loam em seus próprios projetos Go para gerenciar persistência de dados.\n\n```bash\ngo get github.com/aretw0/loam\n```\n\n### Exemplo\n\n```go\npackage main\n\nimport (\n \"context\"\n \"fmt\"\n \"log/slog\"\n \"os\"\n\n \"github.com/aretw0/loam/pkg/core\"\n \"github.com/aretw0/loam\"\n)\n\nfunc main() {\n // 1. Inicializar Serviço (Factory) com Functional Options.\n // O primeiro argumento é a URI ou Path do cofre. Para o adapter FS, use o caminho do diretório.\n service, err := loam.New(\"./meus-docs\",\n  loam.WithAdapter(\"fs\"), // Padrão\n  loam.WithAutoInit(true), // Cria diretório e git init se necessário\n  loam.WithLogger(slog.New(slog.NewTextHandler(os.Stdout, nil))),\n )\n if err != nil {\n  panic(err)\n }\n\n // NOTA DE SEGURANÇA (Dev Experience):\n // Ao rodar via \"go run\" (Dev Mode), o Loam isola escritas em um diretório temporário para proteger seus dados.\n // Para ferramentas que apenas lêem (como CLIs de análise), use WithReadOnly(true) para acessar os arquivos reais com segurança:\n //\n // service, err := loam.New(\".\", loam.WithReadOnly(true)) // Bypass Sandbox (Read-Only)\n\n\n ctx := context.Background()\n\n // 2. Escrever (Save)\n // Salvamos o conteúdo com uma \"razão de mudança\" (Commit Message)\n // Isso garante que toda mudança tenha um porquê.\n ctxMsg := context.WithValue(ctx, core.ChangeReasonKey, \"documento inicial\")\n err = service.SaveDocument(ctxMsg, \"daily/hoje\", \"# Dia Incrível\\nComeçamos o projeto.\", nil)\n if err != nil {\n  panic(err)\n }\n fmt.Println(\"Documento salvo com sucesso!\")\n\n // 3. Ler (Read)\n doc, err := service.GetDocument(ctx, \"daily/hoje\")\n if err != nil { // Tratamento simplificado\n  panic(err)\n }\n fmt.Printf(\"Conteúdo recuperado:\\n%s\\n\", doc.Content)\n\n // ... (veja exemplos completos em examples/basics/crud)\n}\n```\n\n### Typed Retrieval (Generics)\n\nPara maior segurança de tipos, você pode usar o wrapper genérico:\n\n```go\ntype User struct { Name string `json:\"name\"` }\n\n// Abre um repositório já tipado (leitura/escrita de User)\n// O ID do documento é preservado, mas o conteúdo é mapeado para User.\nuserRepo, err := loam.OpenTypedRepository[User](\"./meus-docs\")\nif err != nil {\n    panic(err)\n}\n\n// Acesso tipado\nuser, _ := userRepo.Get(ctx, \"users/alice\")\nfmt.Println(user.Data.Name) // Type-safe!\n```\n\n### Reactivity (Watch)\n\nVocê pode observar mudanças em repositórios tipados para implementar \"Hot Reload\" de configurações ou interfaces reativas:\n\n```go\n// Retorna um canal de core.Event\n// Opcional: Use WithWatcherErrorHandler para capturar falhas de acesso a arquivos durante o monitoramento.\nevents, err := userRepo.Watch(ctx, \"users/*\", loam.WithWatcherErrorHandler(func(err error) {\n    fmt.Printf(\"Erro no watcher: %v\\n\", err)\n}))\n\ngo func() {\n    for event := range events {\n        fmt.Printf(\"Mudança detectada em %s\\n\", event.ID)\n        // Recarregue o documento tipado se necessário\n        newUser, _ := userRepo.Get(ctx, event.ID)\n    }\n}()\n```\n\n## 📂 Exemplos e Receitas \u003ca name=\"examples\"\u003e\u003c/a\u003e\n\n### Demos (Funcionalidades do Core)\n\n- **[Hello World](examples/basics/hello-world)**: O ponto de partida.\n- **[CRUD Básico](examples/basics/crud)**: Create, Read, Update, Delete.\n- **[Formats](examples/demos/formats)**: Suporte nativo a JSON, YAML, CSV e Markdown.\n- **[Read-Only Mode](examples/demos/readonly)**: Acesso seguro em desenvolvimento.\n\n\u003e 📚 **[Ver todos os exemplos e receitas](./examples/README.md)** (incluindo Calendar, Ledger, e automações avançadas).\n\n### Recipes (Casos de Uso)\n\n- **[CLI Scripting](examples/recipes/cli_scripting)**: Como converter dados usando Pipes e Shell (Bash/PowerShell).\n- **[ETL \u0026 Migration](examples/recipes/etl_migration)**: Migração de dados legados.\n\n## 📚 Documentação Técnica \u003ca name=\"tech-docs\"\u003e\u003c/a\u003e\n\n- [Visão do Produto](docs/PRODUCT.md)\n- [Arquitetura Técnica](docs/TECHNICAL.md)\n- [Roadmap \u0026 Planning](docs/PLANNING.md)\n\n### Tuning de Performance\n\nSe sua aplicação lida com **rajadas massivas de eventos** (ex: `git checkout` em repositórios enormes) e você nota que o watcher \"congela\", pode ser necessário aumentar o buffer de eventos para evitar bloqueios:\n\n```go\n// Aumenta o buffer para 1000 eventos (Padrão: 100)\nsrv, _ := loam.New(\"path/to/vault\", loam.WithEventBuffer(1000))\n```\n\n## Known Issues \u003ca name=\"known-issues\"\u003e\u003c/a\u003e\n\n### Linux/inotify\n\n- Devido a limitações do `inotify`, novos diretórios criados *após* o início do watcher **não** são monitorados automaticamente (é necessário reiniciar o processo ou recriar o watcher). Em Windows e macOS, isso geralmente funciona nativamente.\n- Repositórios muito grandes (milhares de diretórios) podem exceder o limite de *file descriptors*. Aumente o limite via `sysctl fs.inotify.max_user_watches` se necessário.\n\n### CSV \u0026 Nested Data\n\n- O Loam agora suporta **Smart CSV**, que detecta estruturas JSON aninhadas (`map`, `[]interface{}`) e as preserva automaticamente.\n- **Caveat (False Positives)**: Strings que parecem JSON (ex: `\"{foo}\"`) podem ser interpretadas como objetos se não estiverem escapadas (ex: `\"\\\"{foo}\\\"\"`). Em casos de ambiguidade, o parser favorece a estrutura.\n- **Concorrência**: A escrita em coleções (CSV) não possui locking de arquivo (flock). O uso concorrente por múltiplos processos pode resultar em perda de dados (Race Condition no ciclo Read-Modify-Write).\n\n### Strict Mode \u0026 Large Integers\n\n- O modo estrito (`strict: true`) preserva inteiros grandes usando `json.Number`.\n- **Limitação de Performance**: Ocorre uma pequena penalidade de performance devido à normalização recursiva necessária para garantir que formatos como YAML e Markdown comportem-se identicamente ao JSON.\n- **Recomendação**: Use `strict: true` se sua aplicação depende fortemente de IDs numéricos de 64 bits ou precisão decimal exata em metadados aninhados.\n\n## Status\n\n🚧 **Alpha**.\nA API Go (`github.com/aretw0/loam`) e a CLI são estáveis para uso diário (Unix Compliant).\n\n## Licença\n\n[AGPL-3.0](LICENSE.txt)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faretw0%2Floam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faretw0%2Floam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faretw0%2Floam/lists"}