A base fixa compartilhada fica configurada no .env:
POCKETWIKI_REFERENCE_PATH="/absolute/path/to/reference/wiki"
POCKETWIKI_REFERENCE_READONLY=trueO contrato local fica em SKILL/connection.md.
Existem duas formas de carregar a base:
- Base fixa no servidor: configure
POCKETWIKI_REFERENCE_PATHno.env. Essa é a opção para celular/outros PCs na mesma rede, porque todos leem a wiki direto da máquina principal. - Abertura manual: use
Abrir pasta/Fallbackno navegador. Nesse caso o handle fica no IndexedDB daquele navegador/dispositivo e serve como modo local/ad-hoc.
Quando rodar pelo server.mjs e o path do .env existir, ele tem prioridade como fonte compartilhada.
As APIs /api/config e /api/wiki/files releem essa configuracao durante a execucao, entao ajustes no POCKETWIKI_REFERENCE_PATH passam a refletir no proximo reload da pagina. O path aceita absoluto, relativo ao projeto, ~/..., $HOME/..., file://... e espacos escapados copiados do terminal.
O endpoint PUT /api/v1/solutions/{solution_id} grava documentos revisados pelo PocketTrace em solutions/{solution_id}.md. A revisão remota é o SHA-256 dos bytes persistidos, então qualquer edição manual muda o ETag e força nova confirmação antes de overwrite.
Habilite escrita explicitamente:
POCKETWIKI_REFERENCE_READONLY=false
POCKETWIKI_WRITE_TOKEN="<segredo-longo-aleatorio>"Sem token, a escrita falha fechada com 503. Em modo read-only retorna 403. O token não aparece em /api/config, /api/routes, logs ou metadados. O limite padrão é 8 MiB e pode ser aumentado com POCKETWIKI_WRITE_MAX_BYTES; valores menores são ignorados.
Criação:
curl --fail-with-body \
-X PUT \
-H "Authorization: Bearer $POCKETWIKI_WRITE_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Idempotency-Key: solution_demo:doc_v1' \
--data-binary @solution.json \
https://pocketwiki.example/api/v1/solutions/solution_demoAtualização condicional:
curl --fail-with-body \
-X PUT \
-H "Authorization: Bearer $POCKETWIKI_WRITE_TOKEN" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Idempotency-Key: solution_demo:doc_v2' \
-H 'If-Match: "sha256:REVISAO_OBSERVADA"' \
--data-binary @solution-v2.json \
https://pocketwiki.example/api/v1/solutions/solution_demoUse HTTPS no cliente, normalmente com Tailscale Serve ou reverse proxy apontando para o servidor local. O contrato completo está em docs/technical-contract/pockettrace/01_contrato_api_ingestao_solutions.md.
Arquivos .excalidraw, .excalidraw.md e Markdown gerado pelo plugin Obsidian Excalidraw entram como fontes da wiki. Ao abrir uma pagina desse tipo, a UI prioriza a aba Excalidraw; o botao Abrir indice força a leitura textual quando precisar ver o markdown bruto.
O fluxo atual:
- detecta cenas JSON puras de
.excalidraw - descompacta blocos
## Drawingcom fencecompressed-jsonusando LZString - interpreta fences
jsonquando o Obsidian grava a cena sem compressao - renderiza a cena completa em SVG com
@excalidraw/utils(exportToSvg) - no app macOS, abre um editor Excalidraw completo via
WKWebViewusando@excalidraw/excalidraw - salva alterações direto na wiki local com botao Salvar,
Cmd+Se autosave; fontes remotas ficam em modo somente leitura - usa fallback textual quando so existem
Text Elementsdisponiveis - mostra se a visualizacao veio de
cena completaoufallback textual - extrai textos, links, tags e relacoes por setas/bindings para busca, mapa, saude e contexto da IA
O renderer oficial web e o editor desktop ficam empacotados localmente e so carregam quando a aba Excalidraw e aberta. Para gerar ou atualizar os bundles:
npm run build:excalidrawEsse comando atualiza assets/excalidraw-renderer.js, assets/lz-string.min.js e Sources/PocketWikiMac/Resources/ExcalidrawEditor/. Rode depois de npm install ou quando mexer em src/excalidraw-renderer.js ou src/excalidraw-desktop/.
O servidor tambem serve .excalidraw com content-type application/vnd.excalidraw+json, entao esses arquivos entram no mesmo fluxo de leitura, busca e indexacao dos Markdown.
A interface foi ajustada para funcionar de iPhone 13 ate ultrawide. Em telas menores, a navegacao usa botoes compactos por icone e textos reduzidos para evitar sobreposicao.
manifest.webmanifest, sw.js e offline.html formam a casca instalavel do PocketWiki. Se um atalho abrir enquanto o servidor local estiver indisponivel, a tela offline.html mostra um erro visual com acoes de retentar e copiar URL.
Esse cache e apenas da casca do app. A base compartilhada da wiki continua sendo o POCKETWIKI_REFERENCE_PATH no .env; APIs e conteudo indexado nao sao tratados como fonte persistente pelo service worker.
Para trocar o icone da sidebar depois, adicione assets/favicon.png ou favicon.ico na raiz do projeto. Sem arquivo, a UI cai no fallback PW.
Primeira instalacao ou atualizacao de dependencias:
npm install
npm run build:excalidrawA versao desktop macOS fica disponivel em .dmg nas releases do GitHub.
Os bundles macOS incluem o MiddlewareAuth como helper independente. O PocketWiki usa uma instância externa se ela já estiver saudável e só gerencia o processo empacotado que ele próprio iniciou. O limite completo, modos de execução e overrides estão em docs/technical-contract/macos-app/09_middleware_auth_addon.md.
Na aba Servidor, o card MiddlewareAuth mostra health e autenticação como checks separados, permite alternar entre helper local e endpoint remoto e rotaciona a senha do helper local sem trocar a chave que protege os tokens OAuth. Para um MiddlewareAuth externo, o botão Gerar nova senha usa o token atual para chamar POST /v1/auth/client-token/rotate diretamente, salva o novo token neste Mac e valida o acesso. Endpoints públicos exigem HTTPS; o proxy web envia o bearer apenas para a URL autenticada configurada. A senha antiga deixa de funcionar para todos os clientes; o contrato dessa operação fica no repositório MiddlewareAuth em docs/CLIENT_TOKEN_ROTATION.md.
O PocketKernel também possui um card operacional com os modos automatic, managed, external e disabled. No modo local, o PocketWiki inicia o binário empacotado em loopback e gera um wrapper stdio que preserva paths com espaço. Os limites entre os projetos e o contrato de distribuição estão em docs/technical-contract/macos-app/10_pocketkernel_addon.md.
Falhas de inicialização aparecem como alerta global e como ERROR no log da aba Servidor. Se um helper já validado cair, o PocketWiki registra WARNING e tenta recuperá-lo até três vezes em 60 segundos, com backoff de 1, 5 e 15 segundos; uma recuperação bem-sucedida não interrompe o usuário com modal. O alerta global só aparece quando a recuperação falha ou entra em crash loop, e a saída completa fica em ~/Library/Application Support/PocketWiki/{MiddlewareAuth,PocketKernel}/. Os add-ons não fazem auto-update isolado: cada release do PocketWiki publica e valida os refs e SHA-256 dos dois helpers, mostra a diferença da próxima versão na aba Servidor e recusa instalar um pacote inconsistente.
O contrato proposto para integrar toda a família — add-ons internos, aplicações locais independentes e serviços remotos — está na RFC-0001 — Pocket Interop Contract. A RFC inclui schema validável e exemplos para PocketKernel, MiddlewareAuth, PocketTrace e PocketCli.
O chat também mantém transcrições por sessão em JSON legível e uma nota pessoal MEMORY.md local em ~/Library/Application Support/PocketWiki/AI Memory/. A sessão ativa é restaurada ao abrir o app; o menu Sessões retoma conversas anteriores e importa JSON do cockpit web. Cada pergunta recebe até 12 mensagens anteriores e até 4.000 caracteres da nota, permitindo continuar a conversa após trocar de provider/modelo. Com POCKETWIKI_MEMORY_TOKEN configurado, o app envia eventos e recupera trechos pela API interna do servidor PocketWiki, sem depender do MCP oficial do ai-memory. O formato, a configuração e os limites atuais estão em Memória independente do modelo.
No cockpit web, a conversa também é restaurada após recarregar e mantém o contexto ao trocar de provider. Em Sessões, dá para retomar conversas arquivadas e importar/exportar JSON compatível com o app macOS. Para usar a memória compartilhada, configure POCKETWIKI_MEMORY_TOKEN no servidor e informe o mesmo valor em Configurações da IA no navegador. Os registros ficam em arquivos JSON e MEMORY.md sob POCKETWIKI_MEMORY_PATH.
Para gerar e abrir o app local:
./script/build_and_run.sh --verifyPara gerar o instalador localmente:
./script/build_macos_dmg.shO builder gera os arquivos abaixo em dist/release/:
PocketWiki-alpha-<x.y.z>-macOS-universal.dmg
PocketWiki-alpha-<x.y.z>-macOS-universal.zip
PocketWiki-alpha-<x.y.z>-macOS-universal.build.json
*.sha256
O workflow .github/workflows/macos-release.yml roda em todo push na main,
inclusive após merge de qualquer branch. Ele resolve a próxima versão, gera os
arquivos e publica uma GitHub Release canônica. Hoje o canal padrão é alpha,
com tags alpha-x.y.z. Para migrar ao formato tradicional x.y.z, configure a
variável Actions POCKETWIKI_RELEASE_CHANNEL=stable; o mesmo builder e o mesmo
updater passam a usar releases estáveis sem mudança de código.
O versionamento é SemVer e sempre tem os três componentes MAJOR.MINOR.PATCH.
O resolvedor lê as tags alcançáveis pelo HEAD e usa como base a maior versão
numérica encontrada nos formatos alpha-X.Y.Z, X.Y.Z ou no legado vX.Y.Z.
Em empate, a ordem é estável, alpha e legado. O package.json só é usado para
bootstrap quando o histórico não contém nenhuma tag SemVer reconhecida.
| Incremento | Sinal encontrado nos commits desde a tag base | Resultado a partir de 1.2.3 |
|---|---|---|
| Major | tipo!:, BREAKING CHANGE ou [major] |
2.0.0 |
| Minor | feat:, feature: ou [minor] |
1.3.0 |
| Patch | correção, manutenção, documentação ou qualquer fallback | 1.2.4 |
O maior incremento encontrado vence. Se não houver commits após a tag base, a
versão é reutilizada — isso permite promover alpha-1.2.3 diretamente para
1.2.3. Para inspecionar exatamente o que será publicado:
./script/resolve_release_version.sh
POCKETWIKI_RELEASE_CHANNEL=stable ./script/resolve_release_version.shPara um bootstrap controlado sem tags, use
POCKETWIKI_RELEASE_BASE_VERSION=X.Y.Z.
O app consulta as releases no launch e ao voltar ao foco. Quando existe uma
versão canônica mais nova, exibe Atualizar para <tag> no canto superior direito,
baixa o ZIP, valida bundle id, tag interna e assinatura, substitui o app atual e
reabre a nova versão. Também é possível forçar a consulta pelo menu
PocketWiki > Verificar Atualizações....
O build local usa a mesma política do PocketTrace:
cp .env.example .env.localConfigure apenas localmente:
POCKETWIKI_SIGN_MODE="auto"
POCKETWIKI_SIGNING_IDENTITY=""
POCKETWIKI_SKIP_SECRET_SCAN="0"auto procura uma identidade Apple Development ou Developer ID Application no Keychain e assina o bundle sem imprimir nome, e-mail ou Team ID. Para fixar, use o hash do certificado em POCKETWIKI_SIGNING_IDENTITY, nunca a identidade completa. Para build sem conta Apple:
POCKETWIKI_SIGN_MODE=adhoc ./script/build_and_run.sh --verifyO bundle local resolve versão e tag pelo mesmo histórico Git usado pela release, não pelo valor estático do package.json. Ele também não incorpora o caminho do .env: o launcher repassa as variáveis já carregadas ao processo e remove POCKETWIKI_ENV_PATH antes de abrir o app, evitando bloquear a primeira janela no controle de privacidade do macOS. Quando um caminho de configuração é fornecido explicitamente em outro fluxo, apenas arquivo regular UTF-8 de até 1 MiB é aceito.
Antes do build, script/scan_secrets.sh bloqueia .env versionado, certificados/profiles versionados e padrões comuns de developer account no código. Não versionar .env.local, .p8, .p12, .cer, .pem, .key, .mobileprovision, .provisionprofile ou .xcarchive.
Para permitir assinatura pela automação do GitHub, coloque o certificado apenas em Settings > Secrets and variables > Actions, nunca no repositório:
APPLE_CODESIGN_CERTIFICATE_BASE64:.p12exportado e codificado em base64.APPLE_CODESIGN_CERTIFICATE_PASSWORD: senha do.p12.APPLE_CODESIGN_IDENTITY: opcional, hash do certificado. Não use nome, e-mail ou Team ID.
Exporte o certificado localmente e copie só o base64 para o secret:
security export \
-k "$HOME/Library/Keychains/login.keychain-db" \
-t identities \
-f pkcs12 \
-o /tmp/pocketwiki-codesign.p12
base64 -i /tmp/pocketwiki-codesign.p12 | pbcopy
rm -f /tmp/pocketwiki-codesign.p12No workflow .github/workflows/macos-release.yml, se APPLE_CODESIGN_CERTIFICATE_BASE64 existir, a automação cria um keychain temporário no runner, importa o .p12, define POCKETWIKI_SIGN_MODE=auto e roda ./script/build_macos_dmg.sh. Se o certificado não estiver configurado, o workflow cai para POCKETWIKI_SIGN_MODE=adhoc. O ZIP usado pelo updater recebe exatamente a mesma assinatura do app contido no DMG.
Para reduzir o raio de impacto, use environment protection no GitHub: crie um environment release, restrinja quem pode aprovar execuções manuais, mova esses secrets para o environment e adicione environment: release no job release do workflow.
O PocketWiki precisa ficar servido no PC. Deixe este comando rodando no terminal:
npm startNo próprio PC:
http://localhost
Na LAN:
http://pocketwiki.local
http://pokectwiki.local
Rotas detectadas pelo app:
curl http://localhost/api/routesO boot do server tambem imprime URLs locais, LAN e Tailscale quando encontrar IP 100.x.
O server binda em 0.0.0.0 e anuncia nomes .local via mDNS:
POCKETWIKI_BIND_HOST="0.0.0.0"
POCKETWIKI_PUBLIC_HOSTS="pocketwiki.local,pokectwiki.local"
POCKETWIKI_MDNS=trueAo subir, o terminal imprime também URLs por IP, por exemplo:
PocketWiki LAN IP: http://192.168.x.x
No celular, teste primeiro pelo IP. Se o IP funcionar e .local não, o problema é resolução mDNS da rede/cliente.
Checklist se o celular não acessar:
- PC e celular precisam estar na mesma rede/VLAN.
- No macOS, libere conexões de entrada para
nodeem System Settings -> Network -> Firewall. - Se tiver rede guest, mesh com isolamento/AP isolation ou VLAN IoT, o celular pode não alcançar o PC.
- Se
.localfalhar, usehttp://IP_DO_PCou crie entrada DNS/hosts no roteador. - A porta usada para URL sem porta é
80. Se voltar para8787, a URL volta a precisar de:8787.
Browser so omite porta quando o servico esta em HTTP 80 ou HTTPS 443. Registro mDNS/SRV nao faz Chrome/Safari abrirem http://pocketwiki.local em 8787 automaticamente.
Para LAN local sem porta:
npm startO .env deve ter:
POCKETWIKI_PORT=80Depois acesse:
http://pocketwiki.local
Se o SO negar permissao em :80, rode com:
sudo env "PATH=$PATH" npm run start:lan80Se nao quiser rodar Node com privilegio, mantenha 8787 e coloque um reverse proxy local em :80 apontando para 127.0.0.1:8787 (Caddy, Nginx, Traefik ou pf no macOS).
Pelo Tailscale, a URL por IP sempre funciona quando o device esta na tailnet:
tailscale ip -4Exemplo de acesso:
http://100.x.y.z
O .local por mDNS e multicast nao atravessa Tailscale de forma confiavel. Na tailnet, trate o IP 100.x ou o nome MagicDNS .ts.net como caminho nativo.
O PocketWiki tambem lista as rotas detectadas:
curl http://localhost/api/routesExemplo de retorno:
{
"portless": true,
"mdns": ["http://pocketwiki.local"],
"lan": ["http://192.168.x.x"],
"tailscale": ["http://100.x.y.z"]
}Se voce preferir HTTPS pelo nome MagicDNS do Tailscale, use Tailscale Serve:
tailscale serve --bg http://127.0.0.1:80
tailscale serve statusIsso cria uma URL HTTPS sem porta no dominio MagicDNS/Tailscale, algo como:
https://nome-da-maquina.nome-da-tailnet.ts.net
Nao da para fazer pocketwiki.local aparecer automaticamente via Tailscale MagicDNS puro. Para esse nome especifico funcionar na tailnet, use um DNS rewrite/hosts apontando pocketwiki.local para o IP Tailscale do PC e rode o PocketWiki em :80, ou use reverse proxy/DNS interno.
Caminho pratico:
tailscale ip -4Pegue o IP 100.x.y.z do PC e crie uma entrada DNS/hosts:
100.x.y.z pocketwiki.local
Se for no celular, o mais simples costuma ser usar o nome MagicDNS .ts.net ou configurar esse rewrite no DNS que seus clientes usam dentro da tailnet.
Fluxo governado recomendado:
PocketWiki UI/app ou curl
-> PocketKernel /v1/kernel
-> PocketKernel inicia PocketWiki MCP via stdio
-> PocketWiki MCP devolve evidencia
-> ponte loopback do PocketWiki
-> MiddlewareAuth chama LM Studio/OpenAI
-> PocketKernel monta resposta governada
O PocketWiki MCP nao envia mensagens para o PocketKernel. Ele e um servidor stdio que o PocketKernel sobe sob demanda. A UI do PocketWiki so participa desse fluxo quando chama o endpoint HTTP do Kernel.
Config do PocketKernel:
POCKETKERNEL_BASE_URL="http://127.0.0.1:8080"Para subir o PocketKernel consumindo este MCP:
POCKETKERNEL_WIKI_MCP_COMMAND=node \
POCKETKERNEL_WIKI_MCP_ARGS="/Users/irinery/Documents/pocketwiki/src/mcp/pocketwiki-mcp-server.mjs --root /absolute/path/to/reference/wiki" \
go run ./cmd/pocketkernel -mode serve -addr 127.0.0.1:8080Smoke direto no Kernel:
curl -sS http://127.0.0.1:8080/v1/kernel \
-H 'Content-Type: application/json' \
-d '{"text":"Qual é o status do deploy?","channel":"api","app_id":"pocketwiki","user_id":"u1"}'Sinais esperados no JSON:
"profile_used": "wiki""missing_evidence": []quando houver documento confiavel suficiente
Se o MCP nao trouxer evidencia confiavel, o Kernel deve explicitar missing_evidence, por exemplo contexto_requerido_indisponivel ou fonte_confiavel_de_status_operacional.
Provider via MiddlewareAuth:
MIDDLEWARE_BASE_URL="http://127.0.0.1:18787"
MIDDLEWARE_CLIENT_TOKEN="<token do middlewareAuth>"
MIDDLEWARE_PROJECT_ID="acme"
MIDDLEWARE_LLM_PROFILE_ID="default"
LM_STUDIO_BASE_URL="http://127.0.0.1:1234"
LM_STUDIO_MODEL=""O PocketWiki nao chama LM Studio/OpenAI direto para responder. A tela de IA fica compacta: escolhe OpenAI ou LM Studio, modelo e raciocinio; URLs, tokens e API key ficam em configuracoes avancadas. OpenAI usa device code pelo contrato canonico do MiddlewareAuth e acompanha a sessao ate confirmar que o perfil foi persistido; LM Studio registra baseUrl e apiKey no MiddlewareAuth. A pergunta sempre vai para o PocketKernel:
PocketWiki UI
-> MiddlewareAuth /v1/projects/{projectId}/auth/{openai|lmstudio}/...
-> PocketKernel /v1/kernel
-> PocketKernel Harness
-> ponte loopback efemera do PocketWiki
-> MiddlewareAuth /v1/projects/{projectId}/llm/responses
-> LLM/provider configurado
-> resposta governada
No add-on gerenciado, o PocketKernel recebe somente o endereço da ponte e um bearer aleatório válido durante o processo. API key do LM Studio e tokens OpenAI continuam exclusivamente no MiddlewareAuth. A troca de provider/modelo atualiza essa rota em runtime.
Endpoints locais do PocketWiki:
POST /api/kernel/query: proxy para o PocketKernel.POST /api/middleware/lmstudio/api-key: registrabaseUrleapiKeyno MiddlewareAuth.POST /api/middleware/lmstudio/status: consulta status do provider LM Studio no MiddlewareAuth.POST /api/middleware/openai/login: inicia login OpenAI via MiddlewareAuth.POST /api/middleware/openai/status: consulta status OpenAI via MiddlewareAuth.
Nao existem mais /api/ai/chat nem /api/ai/models no PocketWiki. A API key do LM Studio fica em memoria na UI e e enviada ao MiddlewareAuth; o bearer MIDDLEWARE_CLIENT_TOKEN fica no processo do app/servidor e nao e exposto em /api/config.
A aba Saude tem uma area Revisao com melhorias acionaveis e um prompt dedicado em prompts/wiki-review.md. O botao Copiar prompt copia o prompt completo para usar em qualquer LLM; o botao Revisar na IA local manda o mesmo contexto para o modelo local configurado.
A RFC03 esta implementada como servidor MCP local via stdio:
npm run mcp:evidence -- --root "/absolute/path/to/reference/wiki"Ele nao abre HTTP, nao chama LLM e expoe apenas leitura segura:
wiki.searchwiki.get_document
Sem --root, o servidor usa POCKETWIKI_REFERENCE_PATH do .env ou cai no default SKILL/wiki-reference. A resposta de wiki.get_document sempre vem com evidence_only=true e redaction_mode=basic.
Direcao correta: PocketKernel chama este MCP via stdio. PocketWiki UI/app nao chama MCP diretamente e tambem nao "liga" o MCP; quando a UI precisa de resposta governada, ela chama POST /v1/kernel no PocketKernel ou o proxy /api/kernel/query do servidor PocketWiki.
MCP note: mcp.json is for LM Studio/Codex/PocketKernel tools, not for the browser app directly. The filesystem MCP path for this repo should point to:
Use o path absoluto local da sua máquina apontando para SKILL/.
See mcp.example.json.