harness: trazendo o agente de código de volta para dentro do RStudio
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 TerminalNo 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.911Nada 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.