Build an AI Task Server with n8n
Build a private Raspberry Pi server that augments tasks with Hermes Agent.
Introduction
30 Second Summary
Repetitive tasks are easy to capture. Deciding what to do next often takes more thought than moving the information itself.
In this project, you will turn a Raspberry Pi into a private automation server where n8n moves task data through a workflow. Hermes Agent will augment each task with practical guidance for what to do next.
What You'll Build
You will watch a task return to your Mac with useful guidance after travelling through a private workflow on your Raspberry Pi.
By the end of this project, you'll have:
- A private n8n editor you can reach from your Mac through an encrypted SSH tunnel without publishing it to your home network.
- A structured task flow where you enter task, context, and deadline once before n8n carries them forward automatically.
- An augmented task record showing the original fields plus a concise summary, one recommended next action, and one risk.
- Secret Mission: Reboot the Raspberry Pi and prove the n8n editor, Hermes Agent configuration, and saved workflow recover without rebuilding the stack.
Are there any prerequisites?
You need a Raspberry Pi 4 or 5, a compatible power supply, a microSD card with a reader, and a Mac running macOS 12.0 or later. You also need internet access.
No cloud account or paid AI subscription is required.
Before We Start
Before any hands-on work begins, this step anchors the project in a repetitive task from your own world. Your sentence connects the work n8n moves through the workflow with the judgment Hermes Agent adds.
Prepare the Ubuntu Container Host
The task you chose needs a dependable machine before n8n or Hermes Agent can move any data. Your Raspberry Pi becomes that private automation host.
A reproducible 64-bit Ubuntu Server installation gives the Pi a known foundation. SSH public-key authentication protects remote administration.
A verified container runtime proves the host can run the services you add next. This step builds that foundation.
In this step, get ready to:
- Provision Ubuntu Server 26.04.1 LTS for 64-bit ARM on the Raspberry Pi.
- Connect to automation-pi.local with SSH public-key authentication.
- Verify the Docker runtime on arm64.
Install Raspberry Pi Imager and provision Ubuntu
Raspberry Pi Imager writes the operating system to your microSD card. Its configuration wizard also prepares the network plus remote access for headless provisioning.
This project uses Raspberry Pi Imager 2.0.11.1. Check your Mac before choosing the matching setup path.
- Click Finder in the Dock.
- Select Applications in the Finder sidebar.
- Look for Raspberry Pi Imager in the application list.
- Select Raspberry Pi Imager if it is listed.
- Choose File from the menu bar.
- Choose Get Info to read the version in the General section.
✔️ I see the required version
Your Mac already has Raspberry Pi Imager 2.0.11.1. That installation is ready to write the Ubuntu image.
ⓧ I see an older version
The installed copy needs updating so the wizard matches this project.
- Download the current official macOS installer.
- Open the downloaded disk image from your Mac Downloads folder.
- Move Raspberry Pi Imager into your Applications folder.
- Replace the older application when macOS asks.
- Select Raspberry Pi Imager in Finder.
- Press Command-I to check its version.
You should now see 2.0.11.1 in the application information.
ⓧ It is not installed yet
Install Raspberry Pi Imager from its official macOS disk image.
- Download the official macOS installer.
- Open the downloaded disk image from your Mac Downloads folder.
- Move Raspberry Pi Imager into your Applications folder.
- Select Raspberry Pi Imager in Finder.
- Press Command-I to check its version.
You should see 2.0.11.1 in the application information.
An Ed25519 key pair gives your Mac a private identity for SSH access. The private key stays on your Mac while Imager authorizes the matching public key for Ubuntu.
The key generator asks for a file location plus a passphrase. Use the default location and protect the key with a passphrase you can remember.
- Press Cmd+Space to open macOS search.
- Type Terminal and press Enter to open it.
- Use the default key location when the first prompt appears.
- Enter a strong passphrase when the second prompt appears.
- Repeat the passphrase when the final prompt appears.
- Generate the Ed25519 key pair by running this command:
ssh-keygen -t ed25519
What does this command do?
- The ssh-keygen command creates an SSH key pair on your Mac.
- The -t ed25519 option selects the Ed25519 key type used for this server login.
The command confirms that both parts of the key pair were saved. Your Mac now has the identity it needs for encrypted administration.
Seeing an existing-key warning?
- Stop if Terminal asks whether to overwrite an existing key.
- Keep the existing key so other SSH connections continue to work.
Need help choosing a safe path for a second key?
Writing an operating-system image permanently erases the selected microSD card. Check the storage choice carefully before you approve the write.
- Insert the microSD card into your card reader.
- Connect the card reader to your Mac.
- Press Cmd+Space to open macOS search.
- Type Raspberry Pi Imager and press Enter to open it.
- Select your Raspberry Pi 4 or Raspberry Pi 5 model.
- Choose Ubuntu Server 26.04.1 LTS for 64-bit ARM as the operating system.
- Select your microSD card as the storage device.
Why use the 64-bit ARM image?
The Raspberry Pi uses the ARM64 architecture. The 64-bit ARM Ubuntu image gives Docker access to the ARM64 application images used later in this project.
- Set the hostname to automation-pi.
- Choose a non-root Ubuntu username.
- Record that username here: <username>.
- Create a strong local password for the Ubuntu user.
- Configure the network connection used by your Pi.
- Enable SSH public-key authentication.
- Select the Ed25519 public key you generated on your Mac.
What do these settings establish?
- The hostname gives the server the local network address automation-pi.local.
- The non-root user becomes your administrative login.
- The authorized public key lets the Mac prove its identity without sending the private key to the Pi.
Writing plus verification can take several minutes. The application is preparing a bootable server card during this wait.
- Review the selected microSD card one final time.
- Start the image write.
- Approve the storage erase confirmation.
Raspberry Pi Imager should report that writing and verification completed. Your microSD card now contains the configured Ubuntu Server host.
Boot and verify the Ubuntu host
The first boot turns the prepared card into a reachable server. You will connect from the Mac without attaching a monitor or keyboard to the Pi.
The first startup can take a few minutes while Ubuntu initializes the card and network. A short wait before SSH responds is normal.
- Eject the microSD card safely from your Mac.
- Insert the microSD card into the powered-off Raspberry Pi.
- Connect the Raspberry Pi to the configured network.
- Connect the compatible power supply to start the Pi.
- Wait a few minutes for the first boot to finish.
The first SSH connection may ask you to confirm the host identity. SSH may also request the passphrase protecting your private key.
- Return to the Mac Terminal from the key-generation task.
- Use <username> in place of the matching placeholder below.
- Connect to the Raspberry Pi by running this command:
ssh <username>@automation-pi.local
What does this command do?
- The ssh command creates an encrypted remote shell from your Mac.
- The destination combines your selected Ubuntu user with the hostname automation-pi.local.
- Approve the host authenticity prompt if it appears.
- Enter your SSH key passphrase if prompted.
You should reach an Ubuntu command prompt for your selected user. The successful shell proves that the network plus public-key authorization work.
Cannot reach the Pi?
- Confirm the Pi has power and has finished its first boot.
- Confirm the Mac uses the same local network as the Pi.
- Check that the username matches the non-root user configured in Imager.
Still unable to connect?
The architecture check confirms that the Pi is using the required ARM64 platform. The operating-system file identifies the installed Ubuntu release.
- Confirm the architecture and inspect the operating-system details by running these commands:
dpkg --print-architecture
cat /etc/os-release
What do these checks show?
- The first command asks Ubuntu to print the package architecture used by the host.
- The second command displays the identification data stored in /etc/os-release.
You should see arm64 from the architecture check. The release details should identify Ubuntu Server 26.04.1 LTS.
That is the host identity confirmed. Your Mac is administering the correct Ubuntu release on the correct processor architecture.
Install and verify Docker
Docker Engine runs isolated containers on the host. Docker Compose manages several related services as one application stack.
Why Docker Compose for both services?
Docker Compose gives n8n plus Hermes Agent one reproducible lifecycle. It also provides persistent storage plus private service-name networking.
A native Hermes installation beside a containerized n8n instance would create two separate operating models. One Compose stack keeps administration consistent.
Ubuntu 26.04 provides Docker Engine 29.1.3 through the docker.io package. It provides Docker Compose 2.40.3 through docker-compose-v2.
- Refresh Ubuntu's package index by running this command:
sudo apt update
What does this command do?
The command downloads the latest package lists from the configured Ubuntu repositories. The following installation can then select the packages published for this Ubuntu release.
You should see the package lists refresh without repository failures.
Package update failing?
- Confirm the Pi still has network access.
- Check the configured network details if repository connections time out.
Need help diagnosing the update?
The installer may ask for confirmation before downloading the packages. Approving that prompt installs both components from the Ubuntu repositories.
- Approve the package changes when the installation prompt appears.
- Install Docker Engine plus Docker Compose by running this command:
sudo apt install docker.io docker-compose-v2
What does this command install?
- The docker.io package installs Docker Engine from the Ubuntu repositories.
- The docker-compose-v2 package adds the Compose v2 command to the Docker command line.
The package installation should finish without unresolved dependency errors. The host now has the runtime plus the Compose management command.
Installation did not complete?
- Confirm the earlier package update finished successfully.
- Check that the release details identify Ubuntu 26.04.1 LTS.
Need help with a package error?
Before you run the container check, make a quick prediction about whether Docker can reach the registry and start a container.
The first run downloads a small test image, so a short pause is normal.
- Verify Docker Engine by running this command:
sudo docker run --rm hello-world
What does this command prove?
- Docker downloads the test image that matches the host architecture.
- Docker starts the test container and removes it after the process exits.
You should see Docker's confirmation message. That output proves the ARM64 host can download and run a container.
Container check failing?
- Confirm the Docker package installation completed.
- Confirm the Pi can reach the internet to download the test image.
- Include sudo when your Ubuntu user does not have direct Docker socket permission.
Still cannot start the test container?
- Verify Docker Compose v2 by running this command:
sudo docker compose version
What does this command verify?
The command asks the Docker CLI to load its Compose v2 component. A version response confirms that Compose is installed and callable.
You should see a Docker Compose version containing 2.40.3.
The final check starts from the Mac and runs two tests remotely. Make a quick prediction about which two success signals should return through SSH.
- Press Command-T in Mac Terminal to open a new local tab.
- Use <username> in place of the matching placeholder below.
- Verify the remote architecture plus Docker runtime by running this command:
ssh <username>@automation-pi.local "dpkg --print-architecture && sudo docker run --rm hello-world"
What does the final check prove?
- The SSH client runs both checks on automation-pi.local from your Mac.
- The architecture result confirms the Pi uses the required 64-bit ARM platform.
- The container result confirms Docker Engine can start workloads on that platform.
You should see arm64 followed by Docker's confirmation message. Your Ubuntu container host is now reachable and ready for the private n8n service.
Final remote check failing?
- Confirm the username matches the account configured in Raspberry Pi Imager.
- Confirm the earlier local Docker test succeeded on the Pi.
- Enter the SSH key passphrase if Mac Terminal requests it.
Need help interpreting the final output?
Your Raspberry Pi now has a verified Ubuntu foundation with key-based administration plus Docker Compose. Next, you will launch n8n without exposing its editor to the home network.
Launch a Private n8n Instance
Your Raspberry Pi now runs a verified ARM64 container runtime. That foundation is ready to host the automation editor.
Publishing the editor across your home network would expose it to every device on that network. A loopback binding plus an encrypted SSH tunnel gives your Mac private access.
In this step, get ready to:
- Create a Docker Compose configuration for n8n 2.39.6.
- Launch the n8n container with persistent data storage.
- Reach the editor through a private SSH tunnel from your Mac.
Create the private Compose configuration
The compose.yaml file describes how n8n runs on your Pi. Its port binding keeps the editor on the Pi's 127.0.0.1 interface.
- Create the ~/automation-stack directory by running this command:
mkdir -p ~/automation-stack
What does this command do?
The command creates automation-stack inside your Ubuntu user's home directory. The folder holds the Compose configuration for the private services.
- Confirm the new directory exists by running this command:
ls -d ~/automation-stack
What should you see?
You should see the path ending in automation-stack. That output confirms the directory exists on the Pi.
- Enter ~/automation-stack and create compose.yaml in Nano by running:
cd ~/automation-stack
nano compose.yaml
What does this command do?
The first line switches your SSH session into the named project directory. The second line opens a new compose.yaml file in the terminal editor.
- Paste this configuration into compose.yaml.
services:
n8n:
image: n8nio/n8n:2.39.6
container_name: n8n
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true"
volumes:
- n8n_data:/home/node/.n8n
networks:
- automation
networks:
automation:
volumes:
n8n_data:
What does this configuration do?
- The image value pins n8n to 2.39.6 for a reproducible ARM64 deployment.
- The 127.0.0.1:5678:5678 binding makes the editor available only through the Pi's loopback interface.
- The n8n_data persistent volume stores account details plus workflow data under /home/node/.n8n.
- The automation network gives the service a private place to communicate with the agent added later.
- Press Ctrl+O to save compose.yaml.
- Press Enter to confirm the filename.
- Press Ctrl+X to close Nano.
- Confirm the file is present by running:
ls
What should you see?
You should see compose.yaml in the output. The Pi now has the complete configuration needed for the private n8n service.
Can't find compose.yaml?
Check that your terminal is inside ~/automation-stack. Reopen compose.yaml in Nano if the file was not saved.
Make sure the YAML indentation matches the reference. Tabs or missing spaces can change the structure.
Ask for help with the file structure:
✔️ Awesome, I've got everything!
Great. Double-check that compose.yaml is saved inside ~/automation-stack.
ⓧ I'd like to double check the full code
services:
n8n:
image: n8nio/n8n:2.39.6
container_name: n8n
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true"
volumes:
- n8n_data:/home/node/.n8n
networks:
- automation
networks:
automation:
volumes:
n8n_data:
Launch and inspect n8n
Compose now has everything required to create the container. The first start can take a few minutes while Docker downloads the pinned image.
- Start the n8n service in the background by running:
sudo docker compose up -d n8n
What does this command do?
- The up -d portion creates the service in the background.
- The n8n argument starts only the n8n service defined in compose.yaml.
- Docker creates the automation network plus the n8n_data volume from the same file.
Before you inspect the service, do you expect its published address to show every network interface or only the Pi's loopback interface?
- Inspect the running Compose service by running:
sudo docker compose ps
What should you see?
You should see the n8n service running. Its published port should include 127.0.0.1:5678.
That is the first major piece online. Your automation editor now runs persistently without listening across the home network.
Is the n8n service missing?
Confirm that your SSH session is still inside ~/automation-stack. Compose needs to find compose.yaml in that directory.
Check the YAML indentation against the full-code tab if Compose reports a configuration problem.
Get help diagnosing the service:
Open n8n through an SSH tunnel
SSH local port forwarding carries traffic from your Mac's local port to the Pi's loopback port. The browser can reach n8n while the service remains unavailable to other devices.
- Create a second Mac Terminal window by pressing Cmd+N in the Terminal from earlier.
- Start the local port forward by running the command below with <username> replaced by your selected non-root Ubuntu username:
ssh -N -L 5678:127.0.0.1:5678 <username>@automation-pi.local
How does the tunnel work?
The -L option forwards port 5678 on your Mac to 127.0.0.1:5678 on the Pi. The -N option keeps this SSH session focused on forwarding traffic.
- Keep the second Terminal window running while you use n8n.
Before you load the address, do you expect the private editor to be reachable through the new tunnel?
- Click your web browser in the Mac Dock.
- Enter http://localhost:5678 in the address bar.
- Confirm that the n8n owner-account screen loads.
The next form creates credentials for your local editor. Keep its password private by storing it in your password manager.
- Complete each required owner-account field with your local account details.
- Choose a strong password for the local owner account.
- Submit the owner-account form using the button at the bottom.
You should now see the n8n editor in your browser. You have a private automation service with saved account data plus an encrypted path from your Mac.
Can't reach the n8n screen?
Keep the Terminal window running the tunnel command. Closing that window removes the forwarding path.
Confirm that the username in the tunnel command matches the non-root Ubuntu user authorized on automation-pi.local.
Ask for help tracing the connection:
Your private n8n editor is live with persistent storage. Next up, you will build the structured task pipeline that exposes the missing-agent limit.
Build the Task Pipeline
Your private n8n editor is running through the encrypted tunnel from your Mac. It can now take responsibility for structured task data.
Structured task movement and AI augmentation have separate responsibilities. You will build to that boundary and test what the current stack can support.
In this step, get ready to:
- Create a workflow named Task Augmentation Pipeline.
- Shape a task into fixed task, context, and deadline fields.
- Test the augmentation boundary with a health request to the private service address.
Create the workflow structure
A workflow defines the order in which n8n processes data. The first node starts the run before the second node creates the task record.
- Return to the n8n editor at http://localhost:5678 from earlier.
- Use the workflow creation control in the left navigation to start a blank workflow.
- Set the workflow name to Task Augmentation Pipeline in the title field above the canvas.
- Add Manual Trigger as the first node by using the node picker.
- Add Edit Fields (Set) directly after Manual Trigger by using the node picker.
- Rename Edit Fields (Set) to Task Input in the node title.
- Save the workflow using the save control in the editor header.
You should see a two-node workflow with Manual Trigger connected to Task Input.
Cannot find the nodes?
Search for each node by its full name in the node picker. Confirm that Manual Trigger appears first on the canvas.
If the nodes are disconnected, drag a connection from Manual Trigger to Task Input.
Help me connect the Manual Trigger and Edit Fields nodes in n8n.
Structure the task data
The Edit Fields (Set) node gives each piece of task information a stable field name. Later nodes can read those fields without parsing one long sentence.
- Select Task Input on the workflow canvas.
- Choose Manual Mapping in the node settings.
- Add a Fixed field named task with the value Prepare the weekly project update.
Before you run the node, think about the single key you expect to appear in the output.
- Run Task Input using the node execution control.
You should see a JSON object containing the task key with your fixed value.
- Add a Fixed field named context with the value The update must cover progress plus the main blocker.
- Add a Fixed field named deadline with the value Friday at 4 PM.
Before you run the node again, predict how many keys the completed record contains.
- Run Task Input again using the node execution control.
You should now see one structured object containing task, context, and deadline.
- Save Task Augmentation Pipeline using the workflow save control.
Why prepare the fields first?
Separate fields give every later node a predictable input. The workflow can pass each value directly to the exact place that needs it.
This keeps deterministic data preparation inside n8n. AI reasoning stays confined to the augmentation stage.
Fields missing from the output?
Confirm that Manual Mapping is selected. Check that all three field names use lowercase letters.
Run Task Input again after correcting the fields.
Help me fix the structured output from my Task Input node.
Test the augmentation boundary
An HTTP request lets one workflow node call another service. This health check targets the service name reserved for Hermes Agent on the private network.
- Return to the workflow canvas.
- Add an HTTP Request node directly after Task Input.
- Rename the new node to Check Hermes.
You should now see Manual Trigger, Task Input, and Check Hermes connected in sequence.
- Select Check Hermes on the workflow canvas.
- Set Method to GET.
- Set URL to http://hermes:8642/health.
Before you execute the workflow, predict whether the health request can reach its destination.
- Run the complete pipeline by selecting Execute Workflow.
You should see Task Input finish successfully. Check Hermes then reports that it cannot reach http://hermes:8642/health.
Why this failure matters
The successful Task Input output proves that n8n created the structured task record.
Docker Compose service discovery has no hermes service to resolve on the automation network. The request therefore stops at the augmentation boundary.
- Save Task Augmentation Pipeline using the workflow save control.
That intended failure is a useful milestone. Your workflow now owns structured task intake and exposes the missing augmentation service.
Next, you will deploy Hermes Agent on the private network and run this same health check again.
Add Hermes Agent
Your n8n workflow now structures task data successfully. Its final health check still fails because the augmentation service is missing.
In this step, Docker Compose runs Hermes Agent as a separate service on the private network. A named volume preserves the agent's configuration.
The existing Check Hermes request becomes your proof. A successful response shows that n8n can reach Hermes without exposing the agent to your home network.
In this step, get ready to:
- Add Hermes Agent to the existing private Compose stack.
- Protect agent access with a generated bearer token.
- Confirm the existing health request succeeds.
Complete the private stack configuration
The current compose.yaml already defines n8n's private port binding and persistent volume. Hermes joins the same automation network through a separate service definition.
- Switch back to the SSH session for automation-pi.local.
- Move into ~/automation-stack by running this command:
cd ~/automation-stack
What Does This Command Do?
This command places your terminal inside the directory that contains the existing Compose project. The commands in this step use the files stored there.
- In compose.yaml, find this block at the bottom of the file:
networks:
automation:
volumes:
n8n_data:
What Are You Replacing?
This block currently closes the file with one private network and one persistent volume. The replacement keeps both resources while adding the agent service and its storage.
- Replace that block with this expanded configuration:
hermes:
image: nousresearch/hermes-agent:v2026.9.14
container_name: hermes
restart: unless-stopped
command: gateway run
environment:
API_SERVER_ENABLED: "true"
API_SERVER_HOST: "0.0.0.0"
API_SERVER_PORT: "8642"
API_SERVER_KEY: "${API_SERVER_KEY}"
HERMES_GATEWAY_BOOTSTRAP_STATE: "running"
volumes:
- hermes_data:/opt/data
networks:
- automation
networks:
automation:
volumes:
n8n_data:
hermes_data:
What Does This Configuration Do?
- The hermes service runs the pinned ARM64 image with its gateway enabled.
- The API_SERVER_HOST value lets n8n reach the agent across the private Compose network.
- The API_SERVER_KEY value comes from the separate .env file.
- The hermes_data volume preserves agent state under /opt/data.
- Save compose.yaml.
- Choose the tab below that matches how confident you feel about the full file.
✔️ Awesome, I've got everything!
Your saved compose.yaml now defines both services on the private automation network.
ⓧ I'd like to double check the full code
services:
n8n:
image: n8nio/n8n:2.39.6
container_name: n8n
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true"
volumes:
- n8n_data:/home/node/.n8n
networks:
- automation
hermes:
image: nousresearch/hermes-agent:v2026.9.14
container_name: hermes
restart: unless-stopped
command: gateway run
environment:
API_SERVER_ENABLED: "true"
API_SERVER_HOST: "0.0.0.0"
API_SERVER_PORT: "8642"
API_SERVER_KEY: "${API_SERVER_KEY}"
HERMES_GATEWAY_BOOTSTRAP_STATE: "running"
volumes:
- hermes_data:/opt/data
networks:
- automation
networks:
automation:
volumes:
n8n_data:
hermes_data:
Compare this reference with your saved compose.yaml. Keep the spacing beneath services, networks, and volumes aligned exactly.
Compose File Looking Different?
Check that hermes aligns with n8n beneath services. Confirm that hermes_data appears beneath the top-level volumes block.
Help me compare my Compose file with the required Hermes configuration.
The bearer token controls access to an agent that can use terminal tools. Keep the generated value inside .env on the Pi.
- Generate a 64-hex-character bearer token by running this command:
openssl rand -hex 32
What Does This Command Do?
OpenSSL generates a random server secret. The 32 random bytes appear as 64 hexadecimal characters in the terminal.
- Copy the generated token from the terminal.
- Use the same editing method from compose.yaml to create .env inside ~/automation-stack.
- Use this line as the template for .env:
API_SERVER_KEY=your-api-key-here
How Is the Token Loaded?
Docker Compose reads API_SERVER_KEY from .env. It passes the value into the Hermes container without placing the secret inside compose.yaml.
- Replace your-api-key-here with the generated token you copied.
- Save .env.
- Restrict access to .env by running this command:
chmod 600 .env
Why Restrict the File?
The 600 permission mode gives the file owner read and write access. Other users on the Pi receive no access to the token file.
- Choose the tab below to confirm the structure of .env.
✔️ My generated token is saved
Your .env file contains one API_SERVER_KEY line with your generated token in place of the placeholder.
ⓧ I'd like to double check the file
API_SERVER_KEY=your-api-key-here
This reference uses a redacted placeholder. Your saved file must contain the generated token in place of your-api-key-here.
Token File Trouble?
Confirm that .env contains one API_SERVER_KEY line. Make sure the generated token replaces the placeholder without spaces around the equals sign.
Help me check my Hermes token file safely.
Configure Hermes Agent
Hermes stores its provider selection and mutable state in hermes_data. The setup process runs once against that persistent volume.
The first run downloads the Hermes image, so pauses in the terminal are expected. The setup wizard also includes several optional branches.
- Select OpenCode Free when the setup wizard asks for a provider.
- Skip the optional messaging channels when they appear.
- Skip the paid tool providers when they appear.
- Start the interactive setup by running this command:
sudo docker compose run --rm hermes setup
What Does This Command Do?
Docker Compose starts a one-off Hermes container with the service configuration from compose.yaml. The --rm option removes that temporary container after setup finishes.
The named volume remains in place after the temporary container exits. Your provider selection stays available when the permanent service starts.
That is the fiddly part complete. Hermes now has a keyless provider configuration stored in its persistent volume.
Setup Did Not Finish?
Keep the terminal connected while the image downloads. If the wizard exits before saving your provider choice, run the setup command again.
Help me finish the Hermes Agent setup wizard.
Start the stack and verify Hermes
The agent configuration now exists in persistent storage. Starting the full stack turns the failed health check into a direct test of private service discovery.
- Start both Compose services by running this command:
sudo docker compose up -d
What Does This Command Do?
Docker Compose starts n8n and hermes in the background. Both services join the private automation network.
Hermes receives its bearer token from .env. Its API listens inside the container network without publishing a port on the Pi.
Before you check, which two service names do you expect Compose to report?
- Check the service state by running this command:
sudo docker compose ps
What Should You See?
You should see n8n and hermes listed as running. This confirms that the workflow service and augmentation service share the same Compose project.
Hermes Not Running?
Check that the hermes block sits beneath services in compose.yaml. Confirm that .env contains one generated API_SERVER_KEY value.
Help me diagnose why the Hermes container is not running.
- Return to the n8n editor in your browser.
- Return to the saved Task Augmentation Pipeline workflow from earlier.
Before you execute it, do you expect the same connection failure or a response from the new service?
- Click Execute Workflow.
- Select the Check Hermes node after the workflow finishes.
The output panel displays JSON containing "status": "ok". The unchanged request now reaches Hermes at http://hermes:8642/health.
You closed the exact gap the workflow exposed. n8n can now reach a healthy Hermes service entirely through the private network.
Hermes is healthy and persistent. Next, you will replace the health check with the task-augmentation request that adds guidance to each structured task.
Augment Tasks with Hermes
Your private stack is healthy. n8n can now reach Hermes Agent across the private automation network.
The final pipeline needs one judgment-heavy augmentation step. Hermes Agent returns a concise summary, a recommended next action, and a risk.
n8n keeps control of the structured task data. This clean handoff gives the AI one precise job.
In this step, get ready to:
- Create a Header auth credential that protects the Hermes bearer token.
- Convert the health check into an authenticated task-augmentation request.
- Produce a final record containing the original task fields plus Hermes guidance.
Create the Header auth credential
The Hermes API uses bearer-token authentication to decide whether a request is allowed. A Header auth credential lets n8n attach the token without placing it inside the workflow body.
This token protects an API that can run Hermes tools, so treat it like a password. Keep the value inside the credential and outside screenshots.
- Return to Task Augmentation Pipeline in the n8n editor from earlier.
- Select the Check Hermes node on the workflow canvas.
The parameters panel shows the working health request from the previous step.
- Choose Generic Credential Type under Authentication.
- Choose Header auth as the credential type.
The credential selector is now ready for the Hermes authorization header.
- Create a new credential in the credential selector.
The credential form asks for a header name and a header value.
- Enter Authorization as the header name.
- Enter Bearer followed by one space plus the generated API_SERVER_KEY value from .env as the header value.
The secret now lives in the credential form instead of the workflow body.
- Save the credential.
The HTTP Request node now references your saved Header auth credential.
How Does Header Auth Work?
The credential adds an Authorization header to each request. The Bearer prefix tells Hermes Agent to validate the token that follows it.
Keeping this value in a credential prevents the secret from appearing inside the task prompt.
Credential Not Attaching?
- Confirm that Authentication uses Generic Credential Type.
- Confirm that the credential uses Authorization as the header name.
- Confirm that the value starts with Bearer followed by exactly one space.
- Keep the generated token out of screenshots and support posts.
Help me troubleshoot my n8n Header auth credential without exposing the token. You can also ask for help in the n8n community forum.
Convert the health check into augmentation
The existing node already proves that Hermes Agent is reachable. It now needs to send the structured task to the chat-completions endpoint.
- Rename Check Hermes to Augment Task.
- Change Method from GET to POST.
The node is now ready to send task data instead of checking liveness.
- Replace the URL with http://hermes:8642/v1/chat/completions.
- Confirm that your saved Header auth credential remains selected.
The request now targets Hermes Agent's authenticated chat endpoint.
- Turn on Send Body.
- Select JSON for Body Content Type.
The request body controls the model, response style, and task prompt.
- Choose Using JSON for the body.
- Add model with the string value hermes-agent.
Hermes Agent now knows which model identifier the request expects.
- Add stream with the boolean value false.
- Add one messages entry with role set to user.
The request now asks for one complete assistant response.
- Set the message content to Task: {{$json.task}}. Context: {{$json.context}}. Deadline: {{$json.deadline}}. Return a concise task summary, one recommended next action, and one risk to watch..
What Does the Request Send?
- The model value routes the request through hermes-agent.
- The stream value asks for one complete response.
- The n8n expressions read the current task, context, and deadline values from Task Input.
- Predict which response field contains Hermes Agent's guidance.
- Click Execute Workflow to test the request from Manual Trigger.
The Augment Task output contains an assistant response under choices[0].message.content. The response includes the requested summary, next action, and risk.
Request Not Returning Guidance?
- Confirm that the URL is http://hermes:8642/v1/chat/completions.
- Confirm that the method is POST.
- Confirm that stream uses the boolean value false.
Help me diagnose why my authenticated n8n request to Hermes Agent is not returning task guidance.
Build the augmented task record
The Hermes response contains the new guidance, but the current item no longer presents the original task fields as a clean record. A final Edit Fields node combines both sides of the handoff.
- Add a node after Augment Task using the connector on its right side.
- Select Edit Fields (Set) from the node picker.
The new node now sits at the end of the pipeline.
- Rename the node to Augmented Task.
- Select Manual Mapping.
Manual Mapping lets you choose the exact fields in the final task record.
- Map task from the first item produced by Task Input using a named-node expression.
- Map context from the first item produced by Task Input using a named-node expression.
The final node can now recover the first two original fields even though the current item contains the Hermes response.
- Map deadline from the first item produced by Task Input using a named-node expression.
- Map augmentation from {{$json.choices[0].message.content}}.
All four fields now have a defined source.
- Turn on Keep Only Set Fields.
The node output now focuses on the original task fields plus the generated augmentation.
Why Use Named-Node Expressions?
Inside Augmented Task, $json points to the current Hermes response. Named-node expressions reach back to the first item from Task Input.
The augmentation field uses the current response because that is where Hermes Agent placed its guidance.
- Save Task Augmentation Pipeline.
- Predict which four fields the final node should display.
- Click Execute Workflow.
Select Augmented Task after the execution finishes. You should see one record containing task, context, deadline, and augmentation.
You now have the full handoff working. The final record preserves the task fields plus Hermes-generated guidance.
Secret mission
Prove the Stack Survives a Reboot
Restart the entire Raspberry Pi and prove that your private automation server recovers without a rebuild. Confirm that both services, their saved state, and the complete task workflow return.
Clean Up Your Resources
Keeping the stack active does not create a software subscription charge. The Raspberry Pi continues to use electricity while powered.
OpenCode Free model availability can rotate. Choose Pause or Delete if you have finished using the server.
Nice Work!
Nice Work!
You pulled it off! Your Raspberry Pi now runs a private task augmentation server that recovers after a full host reboot.
What you learned:
- Provisioned a headless Ubuntu Server on ARM64 hardware. You secured remote administration with SSH public-key authentication plus an encrypted local port forward.
- Ran pinned n8n plus Hermes Agent containers with Docker Compose. A private network keeps Hermes off the host. Persistent volumes preserve both services' state.
- Built the Task Augmentation Pipeline to carry structured task data through n8n. Hermes returns a concise summary. It also recommends a next action. It flags one risk.
- Secret Mission: Proved automatic service recovery after a full Raspberry Pi reboot. The saved workflow returned an augmented task without rebuilding the stack.
Ready to quiz yourself?