harness: trazendo o agente de código de volta para dentro do RStudio

R
RStudio
agents
LLM
tooling
opensource
Um novo pacote R que abre um agente de código de linha de comando em uma aba de Terminal do RStudio, pré-configurado para um de dezessete papéis profissionais, com skills curadas, system prompt, layout de pastas e gate de execução por auditoria. Com um walkthrough prático da primeira sessão, como os dezessete papéis estão ligados, a ponte de editor do RStudio, e um exemplo trabalhado que roda três coders na mesma tarefa.
Autor

Pedro Carvalho Brom

Data de Publicação

9 de junho de 2026

Code repositorypcbrom/harness

Por vários anos as ferramentas de coding agéntico mais capazes chegaram ao usuário R primeiro como editores dedicados ou como extensões para IDEs de propósito geral. Esse caminho moveu parte do fluxo de trabalho R para fora do RStudio, para um ambiente construído ao redor de outras linguagens. O novo pacote harness reverte o movimento. Os agentes de código modernos de linha de comando são editor-agnósticos: rodam em qualquer terminal, incluindo a aba de Terminal do RStudio. O pacote os conecta ali, ancorados no diretório do projeto, enquanto o console, os gráficos, o painel de ambiente e o data viewer ficam onde o usuário R já trabalha. A sessão agéntica e a sessão analítica voltam a dividir uma janela.

Este é o primeiro release (0.1.0), o segundo pacote da família r-cs-packages, depois do gpumetropolis. Licença MIT, o pacote está no CRAN desde 2026-06-09. O post explica o desenho, percorre uma primeira sessão, mostra como o mesmo papel dirige vários coders lado a lado, e lista os dezessete papéis que vêm na caixa.

O que é

harness::launch() abre uma aba de Terminal pré-configurada para um papel profissional R. O usuário escolhe um papel e um coder suportado (claude, opencode ou codex), o pacote descobre o binário do coder no sistema, gera a configuração, conecta um subconjunto curado de skills do catálogo externo community-skills, escreve um system prompt específico do papel, monta um layout de pastas, e abre o terminal. O agente então roda no lugar, dentro do RStudio.

O pacote nunca chama um language model por si próprio e nunca roda um loop de agente. Faz o bootstrap do ambiente e se afasta. Tudo o que o agente faz a seguir acontece no processo do coder, contra as skills curadas do papel, no diretório do projeto.

Três decisões de desenho

A primeira é curadoria por papel. Em vez de um chat genérico, o agente recebe o subconjunto de skills da comunidade, o system prompt, e o layout de pastas que correspondem a um papel profissional. Um statistician e um package-maintainer recebem skills diferentes, convenções diferentes e pastas de saída diferentes a partir da mesma chamada launch(). O papel é a configuração concreta que o agente lê na inicialização, não uma dica para o modelo.

A segunda é execução audit-first. O agente escreve scripts dentro das pastas do layout do papel e em um decision log por etapa sob logs/, e não roda nada. O usuário roda cada script no console com source(). Nada do que o agente produz alcança o estado da sessão até que uma pessoa leia e escolha rodar.

A terceira é agnosticismo de coder. O mesmo papel dirige qualquer um dos coders suportados pelo seu adapter. Trocar de claude para opencode ou codex não muda o papel, as skills ou a convenção de pastas; só muda o comando de inicialização. Um time pode adotar a camada de papel uma vez e manter a escolha de coder aberta.

Instalação

A versão release está no CRAN:

install.packages("harness")

O build mais recente também está no r-universe:

install.packages("harness",
                 repos = c("https://pcbrom.r-universe.dev",
                           "https://cloud.r-project.org"))

A versão de desenvolvimento está no GitHub:

# install.packages("devtools")
devtools::install_github("pcbrom/harness")

O catálogo community-skills

As skills curadas vêm do catálogo externo community-skills. O pacote nunca o embala: quando o catálogo não está no disco, a primeira chamada de library(harness) aponta para o comando que o busca.

library(harness)
#> harness: community-skills catalogue not found.
#>   Fetch it with:  harness::clone_community_skills()
#>   Or set COMMUNITY_SKILLS_PATH to an existing checkout.

clone_community_skills()

clone_community_skills() escreve o checkout sob ~/.community-skills/, que é um dos caminhos de descoberta default. Para acompanhar upstream depois, rode update_community_skills(); o pacote nunca toca a rede a menos que o usuário chame uma dessas duas funções. Habilite uma atualização automática no attach apenas se você optar, com options(harness.auto_update = TRUE) no .Rprofile.

Uma primeira sessão

Uma sessão típica tem quatro passos. Configurar um papel e abrir um coder:

library(harness)
setup("data-scientist", scaffold = TRUE)   # valida e cria o layout
launch("claude", role = "data-scientist")  # abre o coder na aba de Terminal

No terminal do coder, descreva uma tarefa concreta em linguagem natural. Por exemplo: classificar as espécies do dataset iris, com uma figura exploratória, um split treino/teste estratificado, um modelo multinomial e a acurácia no conjunto de teste. O system prompt do papel já está ativo, então o agente trabalha sob as skills curadas, a convenção de pastas e as regras de auditoria.

O agente então escreve, mas não roda, um script sob o layout do papel e um decision log sob logs/:

analysis/scripts/2026-06-04_iris-classification.R
logs/2026-06-04_01_iris-classification.md

O decision log registra a decisão, sua justificativa e o resultado, deixando o desfecho da execução em branco até a rodada. Você lê o script e o roda no console do R:

source("analysis/scripts/2026-06-04_iris-classification.R")
#> Test accuracy: 0.911

Nada do que o agente produziu alcançou o estado da sessão até você escolher rodar. O padrão é o mesmo para qualquer papel: o pacote monta o andaime, o agente propõe, o usuário executa.

Comparando coders na mesma tarefa

Como o mesmo papel dirige qualquer coder, um único projeto pode rodar vários coders em um problema e manter as saídas separadas. Faça o scaffold do papel uma vez, depois abra cada coder:

setwd("~/work/iris-comparison")
library(harness)
setup("data-scientist", scaffold = TRUE)

launch("claude",   role = "data-scientist")
launch("codex",    role = "data-scientist")
launch("opencode", role = "data-scientist")

Em cada terminal do coder, cole a mesma tarefa e direcione para uma pasta específica do coder. Para o claude:

Classify the iris species. Write a single R script to
analysis/scripts_claude/2026-06-04_iris-classification.R that uses set.seed(42),
a stratified 70/30 split by Species, nnet::multinom, the test-set accuracy and a
confusion matrix, and saves two ggplot2 figures to output/figures/. Follow the
project instructions: native pipe, a short comment above each block, do not
execute anything, only write the script.

Repita nos terminais do codex e do opencode com analysis/scripts_codex/ e analysis/scripts_opencode/. Cada agente escreve seu script e um decision log sob logs/, e não roda nada. Você então lê e roda cada script e compara:

source("analysis/scripts_claude/2026-06-04_iris-classification.R")
source("analysis/scripts_codex/2026-06-04_iris-classification.R")
source("analysis/scripts_opencode/2026-06-04_iris-classification.R")

As pastas separadas mantêm as três implementações lado a lado, e os decision logs registram por que cada agente fez suas escolhas. Uma rodada-exemplo da comparação observou:

Observação claude codex opencode
Escreveu o script, não rodou nada sim sim sim
Escreveu o decision log sim sim variou entre rodadas
Carregou componentes do tidyverse, não o meta-pacote sim sim sim
Acurácia de teste do modelo produzido cerca de 0,91 cerca de 0,91 cerca de 0,91
Estratégia de split por índice rsample::initial_split anti_join

O que se manteve em todo coder é o que o pacote garante: cada agente escreveu no layout do papel, não rodou nada, e deixou a execução para o usuário. O que variou é o que o pacote não fixa: a estratégia de split, a escolha de figuras, e o quão de perto cada agente seguiu cada convenção. Os decision logs tornaram essas escolhas auditáveis depois do fato; as pastas separadas evitaram que as rodadas se sobrescrevessem.

As observações vêm de uma única rodada e dependem das versões do coder e do modelo usados. São registradas como exemplo trabalhado, não como benchmark nem como ranking de coders.

Os dezessete papéis

O release 0.1.0 traz dezessete harnesses de papel. Listados por foco:

Papel Foco
data-scientist análise exploratória e comunicação com o tidyverse
statistician modelos mistos, sobrevida, inferência bayesiana, efeitos marginais
package-maintainer desenvolvimento de pacote, testes, documentação, preparação para o CRAN
paper-author artigos reproduzíveis em R Markdown ou Quarto
data-engineer formatos colunares, engines embarcadas, pipelines de banco de dados
ml-engineer treino tidymodels, avaliação e artefatos de deployment
shiny-developer aplicações Shiny modulares
code-documenter docstrings roxygen2 e sites de referência
econometrician modelos em painel, efeitos fixos, séries temporais
epidemiologist reconstrução de surto e números de reprodução
clinical-biostat derivação CDISC e tabelas regulatórias com o pharmaverse
geospatial-analyst análise vetorial e raster, mapeamento temático
causal-inference difference-in-differences, matching, grafos causais
forecast-specialist previsão de séries temporais com a stack tidyverts
reproducibility-engineer pinagem de dependências e orquestração de pipeline
bioinformatician análise de sequência e expressão com Bioconductor
performance-engineer otimização sob gate duro de equivalência de saída, dirigido pelo pipeline propor-validar-iterar do autoresearch

Cada papel é um descritor YAML que lista as skills a conectar do community-skills, o system prompt, o layout de pastas, e os quality gates. O catálogo é desenhado para crescer: papéis novos são arquivos YAML, não código. Liste os papéis a partir do R com role_list(), inspecione um papel com role_config("data-scientist"), e veja apenas as skills dele com role_skills("data-scientist", available = TRUE).

A ponte de editor do RStudio

Dentro do RStudio, send_selection_to_coder() lê a seleção atual do editor, pede uma nota curta, e envia a nota com uma referência arquivo:linha para o coder rodando no terminal aberto pelo harness. Vincule a um atalho de teclado em Tools, Modify Keyboard Shortcuts, Addins; depois selecione código no editor, pressione o atalho, digite uma nota curta, e a mensagem aterrissa no prompt do coder.

O addin encaminha texto que o usuário escreveu; não roda um loop de agente e não chama um language model. Precisa do RStudio e de um terminal harness aberto.

Decision log

Todo papel carrega uma convenção de decision log. O agente escreve um arquivo Markdown por etapa em logs/, nomeado <AAAA-MM-DD>_<NN>_<slug>.md, com três seções: Decision, Justification e Result. A seção Result lista os arquivos escritos e deixa uma linha para o desfecho da execução, preenchida depois que o usuário roda o script. O diretório logs/ é scaffolded para todo papel, e as entradas formam uma trilha de auditoria que casa cada artefato gerado com o raciocínio por trás dele.

O que não roda no harness

É mais fácil descrever o pacote pelo que ele não tenta fazer. harness não roda inferência, não chama nenhum endpoint LLM, não mantém estado de conversa, não executa código gerado, e não embala o catálogo de skills. A superfície de API de duas linhas para gestão de skills (clone_community_skills(), update_community_skills()) é intencional: o pacote é um launcher e um curador, não uma plataforma de agente.

Onde se posiciona ao lado dos assistentes próprios do RStudio

O harness não compete com os assistentes próprios do RStudio nem com os coders de linha de comando que ele inicia. Os assistentes operam in-process sob assinatura de provedor e são afinados para a superfície do editor. Os coders conduzem a conversa inteira. O harness ocupa o nicho de quem quer o próprio coder, curado por papel, com gate de auditoria em cada linha de código gerado. O ambiente R-nativo hospeda o agente no lugar, curadoria sensível ao papel que uma sessão de terminal genérica não tem é adicionada por cima, e um passo de revisão é exigido antes da execução.

Estado

Este é o primeiro release. API pública: status(), setup(), available_roles(), role(), role_list(), role_skills(), role_config(), launch(), adapters(), scaffold_layout(), community_skills_path(), clone_community_skills(), update_community_skills(), send_selection_to_coder(). A suíte de testes traz 215 expectations e está verde. O pacote está no CRAN desde 2026-06-09 (cran.r-project.org/package=harness); instale com install.packages("harness").

Citação

@software{carvalhobrom_harness_2026,
  title   = {harness: Curated Agentic Harnesses for R Professional Roles (v0.1.0)},
  author  = {Carvalho Brom, Pedro},
  year    = {2026},
  doi     = {10.5281/zenodo.20615126},
  url     = {https://doi.org/10.5281/zenodo.20615126},
  note    = {R package version 0.1.0}
}

O DOI conceito 10.5281/zenodo.20615125 sempre resolve para a versão mais recente.