atman-guru
v0.1.2
Published
Atman, um Guru Digital Interativo para conversa, journal e autoconhecimento.
Downloads
457
Maintainers
Readme
Atman Guru
Atman e um Guru Digital Interativo: uma experiencia web conversacional para reflexao, journal, memoria consentida e acompanhamento de jornada interior. Cada conversa funciona como uma Invocacao do Atma: uma presenca simbolica manifesta na interface para ajudar o usuario a refletir, sem se tornar autoridade absoluta sobre ele.
Instalacao Simples
Requisitos:
- Node.js 20 ou superior;
- Ollama instalado no sistema.
Instalacao global pelo npm:
npm install -g atman-guru
atmanTambem e possivel executar sem instalacao global:
npx atman-guruO comando atman:
- inicia o Ollama quando ele ainda nao estiver ativo;
- baixa
qwen2.5:3bna primeira execucao; - aquece o modelo antes de abrir a interface para reduzir a espera da primeira resposta;
- escolhe uma porta local livre a partir de
3000; - serve API e interface web no mesmo endereco;
- abre o navegador automaticamente;
- salva os dados localmente entre execucoes;
- encerra API e o Ollama iniciado pelo CLI com
Ctrl+C.
Na primeira inicializacao, o terminal exibe o aquecimento do modelo. Durante uma resposta local mais lenta, a interface informa que a geracao continua em andamento e preserva a mensagem para uma nova tentativa se houver falha.
Comandos e opcoes:
atman doctor
atman --no-open
atman --port 3001
atman --model qwen2.5:3b
atman --ollama-url http://localhost:11434
atman --helpO arquivo local fica em uma pasta de dados apropriada ao sistema operacional e
recebe permissao 0600 em sistemas POSIX. Para escolher outra pasta:
ATMAN_DATA_DIR=/caminho/privado atmanO modo local nao instala Prisma, PostgreSQL, Redis ou BullMQ. Essas integracoes sao opcionais e destinadas ao modo servidor do repositorio. Para habilita-las:
npm install @prisma/client@^6.19.3 bullmq@^5.78.1Licenca
Distribuido sob a licenca MIT. Consulte LICENSE.
Direcao Atual
O foco atual do projeto saiu de WhatsApp como canal principal e passou para uma interface web em React. O backend existente continua sendo a base de API, e a experiencia web ja organiza conversa, journal, insights, memoria e controles de privacidade como superficie principal do produto.
O Atman Guru e local-first neste momento: a experiencia prevista roda na maquina do usuario/desenvolvedor, com API local, web local, persistencia em arquivo no CLI e LLM mock ou Ollama sem depender de servicos externos. Deploy publico, cadastro aberto em producao e operacao multiusuario ficam fora do escopo atual; as protecoes de producao permanecem no codigo apenas como base futura.
A memoria do Atman e tratada como um espelho revisavel, nao como arquivo definitivo. O usuario esta juntando fragmentos de quem e; o sistema deve ajudar a lembrar sem cristalizar. Dados essenciais ficam no perfil pessoal, enquanto memorias, journal, insights e marcos de jornada permanecem corrigiveis, arquivaveis e exportaveis.
A "empatia" do Atman deve ser operacional, nao uma alegacao de consciencia literal: contexto da conversa, memoria consentida, linguagem cuidadosa, consciencia situacional e limites claros. A especificacao dessa camada esta em docs/empathetic-context.md.
Estado Atual
Implementacao inicial:
- API Node.js + TypeScript + Express.
- Interface web React + TypeScript em
apps/web. - Busca local no diario e edicao inline de memorias na web.
GET /health.POST /auth/register.POST /auth/login.GET /auth/me.GET /users/:userId/profile.PATCH /users/:userId/profile.GET /me/profile.PATCH /me/profile.POST /chat/messages.GET /conversations/:id.GET /users/:userId/conversations.GET /me/conversations.POST /journal/entries.GET /journal/entries.DELETE /journal/entries/:id.GET /users/:userId/insights.GET /me/insights.DELETE /users/:userId/insights/:id.DELETE /me/insights/:id.GET /users/:userId/journey.GET /me/journey.POST /users/:userId/journey/snapshots.GET /users/:userId/journey/snapshots.POST /me/journey/snapshots.GET /me/journey/snapshots.POST /users/:userId/journey/summaries.GET /users/:userId/journey/summaries.POST /me/journey/summaries.GET /me/journey/summaries.POST /users/:userId/memories.GET /users/:userId/memories.PATCH /users/:userId/memories/:id.DELETE /users/:userId/memories/:id.POST /me/memories.GET /me/memories.PATCH /me/memories/:id.DELETE /me/memories/:id.POST /users/:userId/reminders.GET /users/:userId/reminders.PATCH /users/:userId/reminders/:id.POST /me/reminders.GET /me/reminders.PATCH /me/reminders/:id.GET /practices.GET /knowledge/search.GET /users/:userId/export.DELETE /users/:userId/data.GET /me/export.DELETE /me/data.GET /metrics.GET /webhooks/whatsapp/health.POST /webhooks/whatsapp.- Persona do Atman versionada em codigo.
- Interface interna de LLM.
- Provider DeepSeek.
- Provider mock para desenvolvimento local.
- Guardrails locais iniciais para temas sensiveis.
- Comando natural explicito para salvar journal pelo chat.
- Insights iniciais gerados por worker a partir de entradas de journal.
- Memoria consentida com CRUD, exportacao, exclusao e uso no contexto do chat.
- Perfil pessoal persistente para nome, local atual, timezone, nascimento e notas identitarias.
- Memorias revisaveis com confianca, fixacao e marca de correcao.
- Contexto situacional com memorias ativas, journal recente e insights recentes.
- Analise inicial de jornada com temas recorrentes, reflexao e prompts.
- Filtros de journal por periodo, tag e termo, consumidos pela web.
- Linha do tempo de jornada com journal, insights e memorias.
- Snapshots persistidos de jornada para acompanhar evolucao no tempo.
- Resumos semanais/mensais de jornada gerados apenas por opt-in explicito.
- Lembretes opt-in com status
active,pausedecancelled. - Praticas curtas in-app com notas de seguranca.
- Base de conhecimento curada com metadados, fonte, tipo e busca simples.
- CORS configurado por
WEB_ORIGIN. - Rate limiting HTTP basico configuravel.
- Metricas HTTP e LLM em
/metrics, incluindo tokens, custo estimado e status de circuit breaker. - Protecao contra conflito entre token de sessao e
userIdexplicito em rotas legadas. - Timeout e retry configuraveis para chamadas LLM.
- Webhook WhatsApp generico com token opcional e deduplicacao por evento, mantido como canal externo opcional/legado.
- Exportacao e exclusao de dados por usuario.
- Base BullMQ/Redis para jobs assincronos.
- Prisma/PostgreSQL preparado para usuarios, conversas, mensagens, journal, insights, lembretes e jobs.
- Testes de healthcheck, auth, chat, historico de conversas, journal, memorias, jornada, metricas, dados do usuario, webhook WhatsApp, smoke test Prisma e smoke test BullMQ.
Ao executar o codigo-fonte em desenvolvimento, a persistencia usa memoria por
padrao. O comando empacotado atman ativa automaticamente a persistencia local
em arquivo. Para usar PostgreSQL, configure DATABASE_PROVIDER=prisma.
O repositorio inclui CI no GitHub Actions para validar Prisma, lint, typecheck,
testes, teste de integracao Prisma, build da API e build da web em pushes e
pull requests para main.
Politica De Contratos Autenticados
A interface web deve preferir sessao de usuario: rotas /me/* e endpoints que
aceitam omitir userId quando ha Authorization: Bearer <session-token>.
Endpoints com /users/:userId/* permanecem por compatibilidade com scripts,
testes e integracoes locais, mas sao tratados como legado controlado.
Quando uma rota legada com userId manual tiver equivalente autenticado, a
resposta inclui:
X-Atman-Legacy-User-Route: trueLink: </me/...>; rel="successor-version"
Se uma sessao for enviada junto com userId explicito divergente, a API retorna
403 para evitar acesso cruzado.
Requisitos
- Node.js 20 ou superior.
- npm 10 ou superior.
Setup Local
npm install
cp .env.example .env
npm run devEm outro terminal, suba a interface web:
npm run web:devPor padrao, a API roda em http://localhost:3000 e a web em
http://localhost:5173. A variavel WEB_ORIGIN controla a origem aceita pelo
CORS da API.
Checklist local recomendado antes de consolidar mudancas:
npm run lint
npm run typecheck
npm test
npm run web:test
npm run build
npm run web:buildOs assets de marca da interface ficam em apps/web/public/assets/brand. O app
usa derivados leves para favicon e sidebar, mantendo os PNGs originais como
fonte visual dentro do repositorio.
Os assets dos 22 Arcanos Maiores ficam em
apps/web/public/assets/tarot/major, com PNGs fonte em source, WebP para
desktop em desktop, WebP para mobile em mobile e WebP de alta resolucao para
contemplacao em detail, seguindo o processo descrito em
docs/tarot-asset-workflow.md.
Por padrao, LLM_PROVIDER=mock, entao a API funciona sem chave externa.
Para usar LLM local com Qwen via Ollama:
ollama serve
ollama pull qwen2.5:3bLLM_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen2.5:3b
OLLAMA_NUM_CTX=4096
LLM_TIMEOUT_MS=90000
LLM_MAX_RETRIES=1
LLM_RECENT_MESSAGE_LIMIT=8
LLM_CONTEXT_MEMORY_LIMIT=5
LLM_CONTEXT_JOURNAL_LIMIT=3
LLM_CONTEXT_INSIGHT_LIMIT=3
LLM_MAX_PROMPT_CHARS=10000
LLM_MAX_OUTPUT_TOKENS=700
LLM_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
LLM_CIRCUIT_BREAKER_COOLDOWN_MS=30000No hardware atual analisado para desenvolvimento local (Xeon E5-2680 v4,
32 GiB RAM, RX 550 4 GiB), trate o Qwen local como CPU-first. A GPU AMD pode
continuar sendo usada pelo sistema, mas nao deve ser dependencia do MVP de LLM
local. O qwen3:4b foi testado, mas nesta instalacao consumiu a geracao em
modo thinking e nao entregou resposta final em tempo adequado. Para chat rapido,
o padrao local recomendado passou a ser qwen2.5:3b.
Para medir o provedor local configurado:
LLM_PROVIDER=ollama OLLAMA_MODEL=qwen2.5:3b npm run llm:benchmarkBenchmark recente com qwen2.5:3b: resposta curta em cerca de 8,3s com 58
tokens de saida; resposta mais longa com maxOutputTokens=700 em cerca de
12,1s com 195 tokens de saida. Os testes automatizados forcam
LLM_PROVIDER=mock para nao depender do Ollama real durante validacao.
Astrologia usa um motor local de efemerides por padrao:
ASTROLOGY_EPHEMERIS_PROVIDER=astronomy-engineCom esse provider ativo, o modo invocationMode=astrology injeta no prompt o
ceu geocentrico tropical calculado para o momento atual. Use
ASTROLOGY_EPHEMERIS_PROVIDER=none para desativar essa capacidade. Casas,
ascendente, mapa natal, sinastria e retorno solar ainda exigem data, hora e
local do usuario.
Na web, o modo Astrologia inclui um painel guiado para ceu atual, mapa natal,
transito, sinastria, retorno solar e simbolismo geral. Data, hora e local
aparecem apenas quando a leitura exige esses dados.
Para usar DeepSeek:
LLM_PROVIDER=deepseek
DEEPSEEK_API_KEY=sua-chave
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-chat
LLM_TIMEOUT_MS=30000
LLM_MAX_RETRIES=1
LLM_RECENT_MESSAGE_LIMIT=12
LLM_CONTEXT_MEMORY_LIMIT=8
LLM_CONTEXT_JOURNAL_LIMIT=5
LLM_CONTEXT_INSIGHT_LIMIT=5
LLM_MAX_PROMPT_CHARS=24000
LLM_MAX_OUTPUT_TOKENS=700
LLM_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
LLM_CIRCUIT_BREAKER_COOLDOWN_MS=30000
DEEPSEEK_INPUT_COST_PER_1M_TOKENS_USD=0
DEEPSEEK_OUTPUT_COST_PER_1M_TOKENS_USD=0Os limites LLM_RECENT_MESSAGE_LIMIT, LLM_CONTEXT_*,
LLM_MAX_PROMPT_CHARS e LLM_MAX_OUTPUT_TOKENS controlam custo e latencia do
prompt. O Atman preserva persona e contexto consentido primeiro, depois mantem
as mensagens mais recentes ate caber no orcamento configurado.
O chat tambem usa politica de saida por modo: Reflexao, Taro, Astrologia,
Meditacao e Journal recebem tetos diferentes dentro do limite global. O botao
Continuar envia uma continuacao contextual: o backend ancora a nova resposta
no trecho final da resposta anterior para evitar repeticao e perda do fio.
Na interface web, a continuacao usa rotulos por modo, e o chat possui scroll
com pin inteligente: se o usuario estiver no fim, acompanha a resposta; se ele
subir para ler, aparece Ir ao fim sem puxar a tela agressivamente.
No modo Taro, a interface web pode enviar tarotContext junto da mensagem:
baralho/tradicao, tiragem, pergunta, intencao, descricao visual de baralho
autoral e cartas com posicao/orientacao/notas. Esse contexto entra no prompt
como orientacao operacional e nao altera a mensagem salva no historico.
A aba Taro tambem inclui um ritual visual local focado nos 22 Arcanos Maiores:
embaralhar, cortar, escolher 1, 3 ou 5 cartas, preencher automaticamente a
leitura e enviar ao Atman quando a tiragem se completa. Arcanos Menores ficam
adiados por enquanto para nao tornar a experiencia confusa. O ritual usa assets
autorais responsivos, preview recolhivel da leitura, modo de contemplacao da
carta, camadas de aprofundamento e prompt ajustado para leitura simbolica em
blocos curtos.
As variaveis de custo sao opcionais e devem ser preenchidas com o preco atual
do modelo escolhido por 1 milhao de tokens. O Atman nao fixa uma tabela de
precos no codigo; /metrics apenas calcula uma estimativa a partir do usage
retornado pelo provider e dos valores configurados.
O circuit breaker abre depois de LLM_CIRCUIT_BREAKER_FAILURE_THRESHOLD
falhas consecutivas e volta a permitir uma tentativa depois de
LLM_CIRCUIT_BREAKER_COOLDOWN_MS. Use threshold 0 para desativar.
Para usar PostgreSQL com Prisma:
DATABASE_PROVIDER=prisma
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/atman_guruDepois rode:
docker compose up -d postgres
npm run prisma:generate
npm run prisma:migrate
npm run test:prismaO docker-compose.yml tambem inclui Redis para fases futuras com BullMQ:
docker compose up -d redis
npm run test:queuePara ativar enfileiramento de analise de journal:
JOB_QUEUE_PROVIDER=bullmq
REDIS_URL=redis://localhost:6379Com esse provedor ativo, entradas de journal enfileiram jobs em
journal-pattern-analysis. Para rodar workers localmente:
npm run workerO webhook WhatsApp nao e mais o foco principal do produto, mas segue disponivel como canal externo opcional. Para protege-lo, configure um segredo:
WHATSAPP_WEBHOOK_SECRET=um-segredo-forteQuando essa variavel existe, POST /webhooks/whatsapp exige
Authorization: Bearer <segredo> ou x-webhook-secret: <segredo>.
Para proteger os endpoints de usuario (/chat, /journal, /conversations e
/users), configure:
API_AUTH_TOKEN=um-token-forteQuando essa variavel existe, esses endpoints exigem Authorization: Bearer <token>
ou x-api-token: <token>. Em NODE_ENV=production, API_AUTH_TOKEN e obrigatorio.
Para sessao web, configure um segredo:
JWT_SECRET=um-segredo-com-pelo-menos-16-caracteresEm desenvolvimento, ha um segredo local padrao. Em NODE_ENV=production,
JWT_SECRET deve ser configurado.
O contrato dos endpoints consumidos pela interface web fica disponivel em:
GET /openapi.jsonEsse documento declara x-api-token para protecao operacional da API e
Authorization: Bearer <session-token> para a sessao web em rotas /me.
Para ajustar CORS e rate limit HTTP:
WEB_ORIGIN=http://localhost:5173
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=120Para rotina de retencao em producao:
RETENTION_DAYS=90
RETENTION_INCLUDE_USER_CONTENT=falseCom RETENTION_DAYS=0, a rotina fica desativada. Por padrao,
RETENTION_INCLUDE_USER_CONTENT=false remove apenas dados operacionais antigos:
jobs finalizados, eventos de webhook antigos, memorias ja marcadas como
deleted e lembretes cancelados. Defina RETENTION_INCLUDE_USER_CONTENT=true
somente se a politica do produto permitir remover conversas, journal e insights
mais antigos que o periodo configurado. Snapshots de jornada seguem a mesma
regra de conteudo do usuario.
Scripts
npm run dev # sobe a API em modo watch
npm run web:dev # sobe a interface React em modo desenvolvimento
npm run web:build # valida e gera build da interface React
npm run web:preview # serve o build da interface React
npm run web:test # roda testes de componentes e do cliente web
npm run web:test:watch # roda testes web em modo interativo
npm run worker # sobe workers BullMQ em modo watch
npm run start # executa a API compilada
npm run start:worker # executa workers compilados
npm run build # compila TypeScript
npm run typecheck # valida tipos sem gerar dist
npm test # roda testes
npm run test:prisma # roda smoke test com PostgreSQL local
npm run test:queue # roda smoke test com Redis/BullMQ local
npm run lint # roda ESLint
npm run prisma:generate # gera Prisma Client
npm run prisma:validate # valida schema Prisma
npm run prisma:migrate # aplica migration local
npm run prisma:deploy # aplica migrations em ambiente deploy
npm run prisma:studio # abre Prisma Studio
npm run db:backup # gera dump PostgreSQL em BACKUP_DIR
npm run maintenance:retention # simula a rotina de retencao
npm run maintenance:retention:apply # aplica a rotina de retencao
npm run start:retention # aplica retencao usando build compiladoProducao Opcional
O caminho principal do projeto continua sendo uso local. Esta secao fica como referencia para uma eventual publicacao futura ou instalacao privada mais rigida.
Fluxo minimo de deploy da API, quando esse modo voltar a ser prioridade:
npm ci
npm run prisma:generate
npm run build
npm run web:build
npm run db:backup
npm run prisma:deploy
npm run startWorkers e manutencao devem rodar como processos separados:
npm run start:worker
npm run start:retentionAntes de agendar start:retention, execute npm run maintenance:retention
para conferir o dry-run. Backups do PostgreSQL devem existir antes de usar
RETENTION_INCLUDE_USER_CONTENT=true.
Para enviar erros nao tratados para uma ferramenta externa de observabilidade, configure um webhook HTTPS:
ERROR_REPORT_WEBHOOK_URL=https://observabilidade.exemplo/atman-errosO payload enviado contem metadados tecnicos, nome/mensagem do erro e contexto de rota/processo; corpo de requests, mensagens, journal e memorias nao sao enviados.
Para avaliar alertas operacionais por /health e /metrics, configure:
ALERT_API_BASE_URL=https://api.exemplo.com
ALERT_WEBHOOK_URL=https://observabilidade.exemplo/atman-alertas
ALERT_HTTP_5XX_THRESHOLD=5
ALERT_LLM_ERROR_THRESHOLD=5
ALERT_LLM_LATENCY_RATIO=0.8
ALERT_LLM_DAILY_COST_BUDGET_USD=0Execute uma checagem local com:
npm run monitor:alertsEm producao, apos npm run build, use npm run start:monitor:alerts por
cron/systemd. O comando sai com codigo 2 quando ha alerta ativo, permitindo
integracao tambem por supervisor externo.
Autenticacao Web
Registrar usuario
POST /auth/register
Content-Type: application/jsonBody:
{
"userId": "local-user",
"name": "Opcional",
"password": "senha-com-8-ou-mais-caracteres"
}Resposta:
{
"token": "session-token",
"user": {
"id": "local-user",
"name": "Opcional"
}
}Entrar
POST /auth/login
Content-Type: application/jsonBody:
{
"userId": "local-user",
"password": "senha-com-8-ou-mais-caracteres"
}Sessao atual
GET /auth/me
Authorization: Bearer <session-token>Quando um Authorization: Bearer <session-token> valido e enviado, alguns
endpoints tambem aceitam omitir userId ou usar atalhos /me:
GET /me/profile.PATCH /me/profile.POST /chat/messagespode omitiruserId.POST /journal/entriespode omitiruserId.GET /journal/entriespode omitiruserId.DELETE /journal/entries/:idpode omitiruserId.GET /me/conversations.GET /me/insights.DELETE /me/insights/:id.GET /me/journey.POST /me/memories.GET /me/memories.PATCH /me/memories/:id.DELETE /me/memories/:id.GET /me/export.DELETE /me/data.
Perfil E Memorias Revisaveis
O perfil guarda dados fundamentais que o Atman deve lembrar com mais estabilidade:
nome ou forma de tratamento, local atual, timezone, data/hora/local de nascimento
e notas identitarias. Em modo local com DATABASE_PROVIDER=memory, esse perfil
vive apenas enquanto a API esta rodando. Com DATABASE_PROVIDER=prisma, ele fica
persistido no PostgreSQL.
As memorias guardam fragmentos revisaveis: preferencias, fatos, temas, limites e objetivos. Cada memoria inclui:
confidence:high,mediumoulow.pinned: marca que o fragmento deve ter prioridade no contexto.correctedAt: preenchido quando o conteudo e corrigido.status:active,archivedoudeleted.
O prompt do Atman recebe perfil e memorias com a orientacao de tratar tudo como
apoio revisavel. Se o usuario corrigir uma lembranca, a versao nova deve
prevalecer; a anterior nao deve ser tratada como verdade fixa.
Quando uma resposta usa memorias ativas, o contrato de chat retorna
contextUsage.memories: true e a interface informa esse uso. Novas sugestoes
continuam dependendo de revisao e confirmacao antes de serem salvas.
Endpoints
Healthcheck
GET /healthResposta:
{
"status": "ok",
"service": "atman-guru",
"timestamp": "2026-06-12T00:00:00.000Z"
}Enviar mensagem
POST /chat/messages
Content-Type: application/jsonBody:
{
"userId": "local-user",
"message": "Estou confuso sobre meu trabalho.",
"conversationId": "opcional-uuid",
"invocationMode": "reflection"
}invocationMode e opcional e aceita reflection, tarot, astrology,
meditation ou journal. Ele orienta a Invocacao do Atma no prompt do LLM,
mas nao altera o texto da mensagem salvo no historico. Quando astrology e
usado e ASTROLOGY_EPHEMERIS_PROVIDER=astronomy-engine, o prompt tambem recebe
o ceu astrologico calculado pelo backend.
Resposta:
{
"conversationId": "uuid",
"reply": {
"role": "assistant",
"content": "resposta do Atman",
"provider": "mock",
"model": "local-reflection"
}
}Para resposta em tempo real na interface web, use o endpoint SSE:
POST /chat/messages/stream
Content-Type: application/json
Accept: text/event-streamEventos emitidos:
start: informaconversationId.delta: traz trechos incrementais da resposta.done: traz a resposta final persistida.error: informa falha durante o streaming.
Para salvar uma entrada de journal pelo chat, use um comando explicito:
{
"userId": "local-user",
"message": "registre isso no meu diario: hoje percebi um padrao importante."
}Quando o comando e reconhecido, a resposta inclui journalEntry e o LLM externo nao e chamado.
Consultar conversa
GET /conversations/:id?userId=local-userResposta:
{
"conversation": {
"id": "uuid",
"userId": "local-user",
"createdAt": "2026-06-13T00:00:00.000Z",
"updatedAt": "2026-06-13T00:00:00.000Z",
"messages": []
}
}Retorna 404 quando a conversa nao existe ou nao pertence ao userId informado.
Listar conversas do usuario
GET /users/:userId/conversations?limit=20Resposta:
{
"conversations": [
{
"id": "uuid",
"userId": "local-user",
"createdAt": "2026-06-13T00:00:00.000Z",
"updatedAt": "2026-06-13T00:00:00.000Z",
"messageCount": 2,
"lastMessage": {
"role": "assistant",
"content": "resposta do Atman",
"createdAt": "2026-06-13T00:00:00.000Z"
}
}
]
}Criar entrada de journal
POST /journal/entries
Content-Type: application/jsonBody:
{
"userId": "local-user",
"title": "Opcional",
"content": "Hoje percebi um padrao importante.",
"tags": ["disciplina", "calma"]
}Resposta:
{
"entry": {
"id": "uuid",
"userId": "local-user",
"title": "Opcional",
"content": "Hoje percebi um padrao importante.",
"tags": ["disciplina", "calma"],
"createdAt": "2026-06-13T00:00:00.000Z",
"updatedAt": "2026-06-13T00:00:00.000Z"
}
}Listar journal
GET /journal/entries?userId=local-user&limit=20&from=2026-06-01&to=2026-06-30&tag=foco&q=trabalhoFiltros opcionais:
frometo:YYYY-MM-DDou datetime ISO.tag: tag normalizada do registro.q: termo em titulo, conteudo ou tags.
Resposta:
{
"entries": []
}Sugerir tags de journal
POST /journal/tags/suggest
Content-Type: application/jsonBody:
{
"userId": "local-user",
"title": "Rotina de foco",
"content": "Hoje o trabalho pediu foco e uma pausa para respeitar meu limite.",
"existingTags": ["trabalho"],
"limit": 6
}Resposta:
{
"suggestions": [
{
"name": "foco",
"confidence": "medium",
"reason": "Um termo do registro aponta para este tema."
}
],
"method": "heuristic-keyword-match; suggestions are optional and not stored until the user saves them"
}As sugestoes sao heuristicas, conservadoras e opt-in: nenhuma tag e salva ate o usuario aplicar a sugestao e salvar a entrada.
Excluir entrada de journal
DELETE /journal/entries/:id?userId=local-userRetorna 204 No Content quando a entrada pertence ao usuario e foi excluida.
Se existir um insight heuristico com source associado a essa entrada, ele
tambem e removido.
Listar insights
GET /users/:userId/insights?limit=20Com sessao web, tambem existe:
GET /me/insights?limit=20
Authorization: Bearer <session-token>Cada insight inclui origin, com valores manual, heuristic ou llm, alem
de source para rastrear a origem tecnica.
Apagar insight
DELETE /users/:userId/insights/:idCom sessao web:
DELETE /me/insights/:id
Authorization: Bearer <session-token>Retorna 204 No Content quando o insight pertence ao usuario.
Buscar base de conhecimento curada
GET /knowledge/search?q=espelho&theme=produto&limit=10Resposta:
{
"entries": [
{
"id": "atman-espelho-nao-autoridade",
"title": "Atman como espelho, nao autoridade",
"theme": "produto",
"source": "Nota autoral do projeto Atman",
"type": "author-note",
"confidence": "high",
"summary": "O Atman organiza reflexoes e devolve perguntas.",
"note": "Use esta ideia para manter respostas em tom de companhia reflexiva."
}
],
"method": "curated-local-search; entries are paraphrased or authorial notes and are not automatically injected into chat prompts"
}Tipos de entrada: canonical, interpretation, author-note. A base usa
parafrases e notas autorais; ela nao reproduz textos protegidos integralmente.
Consultar ceu astrologico atual
GET /astrology/current?date=2026-07-16T19:00:00.000Zdate e opcional. Quando omitido, o backend usa o horario atual do servidor.
Resposta:
{
"chart": {
"calculatedAt": "2026-07-16T19:00:00.000Z",
"zodiac": "tropical",
"frame": "apparent-geocentric-ecliptic-of-date",
"source": "astronomy-engine",
"positions": [
{
"body": "Sol",
"longitudeDegrees": 114.26,
"latitudeDegrees": 0,
"sign": "Cancer",
"degreeInSign": 24.26,
"retrograde": false
}
],
"moonPhaseDegrees": 32.71
},
"method": "astronomy-engine; apparent geocentric ecliptic longitude; tropical zodiac; houses require birth/observer data"
}O endpoint calcula Sol, Lua, Mercurio, Venus, Marte, Jupiter, Saturno, Urano, Netuno e Plutao em longitude ecliptica geocentrica tropical. Ele nao calcula casas ou ascendente sem data, hora e local.
Analisar jornada
GET /users/:userId/journey?limit=20&from=2026-06-01&to=2026-06-30Com sessao web:
GET /me/journey?limit=20&from=2026-06-01&to=2026-06-30
Authorization: Bearer <session-token>from e to aceitam YYYY-MM-DD ou datetime ISO. Quando omitidos, a
analise usa os registros mais recentes ate o limite informado.
Resposta:
{
"journey": {
"userId": "local-user",
"generatedAt": "2026-06-13T00:00:00.000Z",
"filters": {
"limit": 20,
"from": "2026-06-01T00:00:00.000Z",
"to": "2026-06-30T23:59:59.999Z"
},
"period": {
"journalEntriesAnalyzed": 0,
"insightsAnalyzed": 0,
"memoriesAnalyzed": 0
},
"method": "Leitura heuristica baseada em tags de diario, tipos de memorias ativas e volume de insights no periodo. Nao e diagnostico nem inferencia clinica.",
"recurringThemes": [
{
"name": "foco",
"count": 2,
"sources": [
{
"type": "journal",
"id": "uuid",
"label": "Registro sem titulo",
"createdAt": "2026-06-13T00:00:00.000Z"
}
]
}
],
"reflection": "Ainda ha pouco material para observar padroes.",
"prompts": []
}
}Linha do tempo de jornada
GET /users/:userId/journey/timeline?limit=50&from=2026-06-01&to=2026-06-30Com sessao web:
GET /me/journey/timeline?limit=50&from=2026-06-01&to=2026-06-30
Authorization: Bearer <session-token>Resposta:
{
"timeline": [
{
"id": "uuid",
"type": "journal",
"occurredAt": "2026-06-13T00:00:00.000Z",
"title": "Registro de diario",
"summary": "Resumo curto do evento.",
"metadata": {
"tags": ["foco"]
}
}
]
}Salvar marco de jornada
POST /users/:userId/journey/snapshots?limit=50&from=2026-06-01&to=2026-06-30Com sessao web:
POST /me/journey/snapshots?limit=50&from=2026-06-01&to=2026-06-30
Authorization: Bearer <session-token>Resposta:
{
"snapshot": {
"id": "uuid",
"userId": "local-user",
"createdAt": "2026-06-13T00:00:00.000Z",
"analysis": {
"userId": "local-user",
"generatedAt": "2026-06-13T00:00:00.000Z",
"period": {
"journalEntriesAnalyzed": 1,
"insightsAnalyzed": 0,
"memoriesAnalyzed": 1
},
"recurringThemes": [],
"reflection": "Leitura contextual da jornada.",
"prompts": []
}
}
}Listar marcos de jornada
GET /users/:userId/journey/snapshots?limit=10Com sessao web:
GET /me/journey/snapshots?limit=10
Authorization: Bearer <session-token>Comparar marcos de jornada
GET /users/:userId/journey/snapshots/compareSem parametros, compara os dois marcos mais recentes. Para escolher marcos especificos:
GET /users/:userId/journey/snapshots/compare?fromSnapshotId=<uuid>&toSnapshotId=<uuid>Com sessao web:
GET /me/journey/snapshots/compare
Authorization: Bearer <session-token>Resposta:
{
"comparison": {
"userId": "local-user",
"generatedAt": "2026-06-13T00:00:00.000Z",
"fromSnapshot": {
"id": "uuid",
"createdAt": "2026-06-01T00:00:00.000Z"
},
"toSnapshot": {
"id": "uuid",
"createdAt": "2026-06-13T00:00:00.000Z"
},
"periodDelta": {
"journalEntriesAnalyzed": 2,
"insightsAnalyzed": 0,
"memoriesAnalyzed": 1
},
"themes": {
"emerging": [],
"intensifying": [],
"reducing": [],
"stable": []
},
"reflection": "Comparacao contextual entre marcos salvos."
}
}Criar resumo periodico de jornada
Resumos periodicos sao opt-in: a criacao exige optIn: true no corpo da
requisicao. O periodo aceito e weekly ou monthly; referenceDate define a
semana ou mes usado como referencia.
POST /users/:userId/journey/summaries
Content-Type: application/jsonCom sessao web:
POST /me/journey/summaries
Authorization: Bearer <session-token>
Content-Type: application/jsonCorpo:
{
"period": "weekly",
"optIn": true,
"referenceDate": "2026-07-16",
"limit": 50
}Resposta:
{
"summary": {
"id": "uuid",
"userId": "local-user",
"period": "weekly",
"startedAt": "2026-07-13T00:00:00.000Z",
"endedAt": "2026-07-19T23:59:59.999Z",
"createdAt": "2026-07-16T00:00:00.000Z",
"analysis": {
"userId": "local-user",
"generatedAt": "2026-07-16T00:00:00.000Z",
"period": {
"journalEntriesAnalyzed": 1,
"insightsAnalyzed": 0,
"memoriesAnalyzed": 1
},
"recurringThemes": [],
"reflection": "Leitura contextual da jornada.",
"prompts": []
}
}
}Listar resumos periodicos
GET /users/:userId/journey/summaries?limit=10&period=weeklyCom sessao web:
GET /me/journey/summaries?limit=10&period=monthly
Authorization: Bearer <session-token>Criar memoria
POST /users/:userId/memories
Content-Type: application/jsonBody:
{
"type": "preference",
"content": "Prefiro respostas mais diretas."
}Tipos aceitos: preference, fact, theme, limit, goal.
Sugerir memoria derivada
POST /users/:userId/memories/suggest
Content-Type: application/jsonCom sessao web:
POST /me/memories/suggest
Authorization: Bearer <session-token>
Content-Type: application/jsonBody:
{
"source": "chat",
"text": "Prefiro respostas mais diretas quando estou sobrecarregado.",
"limit": 3
}Resposta:
{
"suggestions": [
{
"type": "preference",
"source": "chat-command",
"content": "Prefiro respostas mais diretas quando estou sobrecarregado.",
"confidence": "high",
"reason": "O texto expressa uma preferencia explicita do usuario."
}
],
"method": "heuristic-explicit-memory-candidates; suggestions are not stored until the user confirms them"
}Sugestoes de memoria sao conservadoras e nao sao salvas automaticamente. Para
ativar uma sugestao, o cliente deve enviar POST /memories com o conteudo
revisado pelo usuario.
Listar memorias
GET /users/:userId/memories?status=active&limit=50Status aceitos: active, archived, deleted.
Atualizar memoria
PATCH /users/:userId/memories/:id
Content-Type: application/jsonBody:
{
"status": "archived",
"content": "Prefiro respostas curtas e diretas."
}Apagar memoria
DELETE /users/:userId/memories/:idRetorna 204 No Content quando a memoria pertence ao usuario e foi apagada.
Criar lembrete
POST /users/:userId/reminders
Content-Type: application/jsonCom sessao web:
POST /me/reminders
Authorization: Bearer <session-token>
Content-Type: application/jsonBody:
{
"text": "Escrever no diario.",
"cron": "0 8 * * *",
"timezone": "America/Bahia",
"optIn": true
}optIn: true e obrigatorio. Quando JOB_QUEUE_PROVIDER=bullmq e cron existe,
o lembrete e agendado na fila reminders.
Listar lembretes
GET /users/:userId/reminders?limit=20Com sessao web:
GET /me/reminders?limit=20
Authorization: Bearer <session-token>Resposta:
{
"reminders": []
}Atualizar status do lembrete
PATCH /users/:userId/reminders/:id
Content-Type: application/jsonCom sessao web:
PATCH /me/reminders/:id
Authorization: Bearer <session-token>
Content-Type: application/jsonBody:
{
"status": "paused"
}Status aceitos: active, paused, cancelled.
Listar praticas curtas
GET /practicesResposta:
{
"practices": [
{
"id": "breathing-3-4-6",
"type": "breathing",
"title": "Respiracao 3-4-6",
"durationMinutes": 3,
"steps": ["Inspire pelo nariz contando ate 3."],
"prompt": "O que mudou no corpo depois de alguns ciclos de respiracao?",
"safetyNote": "Esta pratica nao substitui cuidado medico."
}
]
}As praticas sao conteudo in-app, nao lembretes. Notificacoes continuam exigindo opt-in explicito via lembretes.
Exportar dados do usuario
GET /users/:userId/exportResposta:
{
"data": {
"userId": "local-user",
"exportedAt": "2026-06-13T00:00:00.000Z",
"conversations": [],
"journalEntries": [],
"insights": [],
"journeySnapshots": [],
"journeySummaries": [],
"memories": [],
"reminders": [],
"whatsappEvents": []
}
}Excluir dados do usuario
DELETE /users/:userId/dataResposta:
{
"userId": "local-user",
"deleted": {
"conversations": 1,
"journalEntries": 1,
"insights": 1,
"journeySnapshots": 1,
"journeySummaries": 1,
"memories": 1,
"reminders": 1,
"whatsappEvents": 0,
"userRecord": false
}
}No modo Prisma, userRecord indica se o registro User tambem foi removido.
Metricas
GET /metricsResposta:
{
"metrics": {
"startedAt": "2026-06-13T00:00:00.000Z",
"uptimeSeconds": 10,
"http": [
{
"method": "GET",
"route": "/health",
"statusCode": 200,
"count": 1
}
],
"llm": [
{
"provider": "mock",
"model": "local-reflection",
"status": "success",
"count": 1,
"totalLatencyMs": 4,
"averageLatencyMs": 4,
"inputTokens": 120,
"outputTokens": 42,
"totalTokens": 162,
"estimatedCostUsd": 0
}
]
}
}Para DeepSeek, inputTokens, outputTokens e totalTokens vêm do campo
usage da resposta do provider. estimatedCostUsd usa
DEEPSEEK_INPUT_COST_PER_1M_TOKENS_USD e
DEEPSEEK_OUTPUT_COST_PER_1M_TOKENS_USD; se esses valores forem 0, a metrica
continua informando uso sem estimar custo.
O status de LLM pode ser success, error ou circuit-open.
Runbook de producao: docs/production-runbook.md.
Checklist de seguranca: docs/security-checklist.md.
Exemplos de agendamento e alertas: docs/ops.
Healthcheck WhatsApp Opcional
GET /webhooks/whatsapp/healthResposta:
{
"status": "ok",
"service": "atman-guru-whatsapp",
"timestamp": "2026-06-13T00:00:00.000Z"
}Receber mensagem do WhatsApp Opcional
POST /webhooks/whatsapp
Content-Type: application/jsonBody minimo:
{
"eventId": "evento-unico-do-provedor",
"phone": "+55 71 99999-0000",
"text": "Hoje estou inquieto."
}Campos equivalentes tambem sao aceitos para facilitar adaptacao ao provedor:
- ID do evento:
eventId,messageId,id,message.id,data.message.id. - Remetente:
phone,from,sender,contact.phone,data.from. - Texto:
text,body,message,message.text,data.message.text.
Resposta:
{
"status": "processed",
"duplicate": false,
"userId": "whatsapp:5571999990000",
"conversationId": "uuid",
"reply": "resposta do Atman"
}Eventos repetidos com o mesmo eventId retornam:
{
"status": "duplicate",
"duplicate": true,
"userId": "whatsapp:5571999990000"
}Proximos Passos
O plano operacional detalhado esta em
docs/next-implementation-plan.md.
Ordem recomendada:
- Polir o fluxo central da conversa: sessoes longas, scroll final, controles recolhidos, botao
Continuar, Markdown e mobile. - Refinar a voz do Atman com testes reais de Taro, Astrologia, meditacao, reflexao e limites.
- Refinar Taro com assets autorais dos 22 Arcanos, area de foco da carta revelada, tiragens mais ricas e preferencia de baralho; reavaliar Arcanos Menores apenas quando houver uma UX clara.
- Expandir Astrologia guiada para mapa natal, transito, sinastria e retorno solar sem inventar dados pessoais.
- Melhorar memoria e personalizacao com preferencias simbolicas consentidas.
- Manter modo local limpo: sem token/auth na experiencia cotidiana.
- Calibrar
LLM_MAX_PROMPT_CHARS,LLM_MAX_OUTPUT_TOKENS, thresholds e latencia conforme uso real. - Opcional para producao: apontar
ALERT_WEBHOOK_URLpara o provedor real de observabilidade. - Manter
/openapi.jsonsincronizado quando novos fluxos web forem criados.
