DeepSeek Harness - Full Tutorial for Beginners
Timestamps
- - intro
- - Getting Started
- - Getting an API Key
- - Setting up a Workspace
- - First Prompt
- - Important Config
- - Initialize our Project
- - Creating a Vault
- - Creating Skills
- - Deterministic Behavior
- - Permissions and Plugins
- - Create a Detailed Spec
- - Deepseek Harness Subagents
- - Reviewing our Spec
- - Working with other Models
- - Local Models
- - Different Provider Subagents
- - Project Review
DeepSeek Harness is a potential alternative to things like Claude Code or Codex. Whenever you hear the term harness when it comes to LLMs, that is the software written around the LLM for you to interact with it. The model is the LLM, and the harness is what wraps everything around it: the tools, the chat, the history, all of that.
So when you're running the DeepSeek software, that's not the LLM itself. And the fact that it's a general harness means we can run pretty much any model from it, DeepSeek's own models, Claude, ChatGPT, or local models through Ollama (which lets you follow along completely free). We'll get all of that set up in this lesson, plus skills, subagents, a vault for your project, permissions and hooks, and a spec-driven build to tie it all together.
Getting Started
You can find DeepSeek Harness at https://deepseek.com. At the time of this recording this is a very new thing, but I'll try to teach it in a way that holds up even as it changes.
You can go to the GitHub to see the latest version of everything (wildly popular right now with 127,000 stars, and it's open source with an MIT license). But you don't have to go through GitHub, you can just install with the quick start command from their page:
npx @deepseek-ai/dsh web
The version I got had an RC on the end, release candidate, so some of the little details might change as that version goes up. If you get an error about npx not being a thing, you'll need to install Node first from https://nodejs.org.
The way this works is it's a web interface. For me it created it on port 3080, so you can copy that URL or command-click it. DeepSeek is a Chinese company, so you might occasionally see a "translate to English" prompt in your browser.
💡 Tip[!tip]
DeepSeek Harness 0.1 "remains in testing for harness developers" as I record this, and a few things are a little wonky. I remember using Google Antigravity the first week it was released, and the agent manager had some kind of memory leak and would eventually just stop working. That's just part of getting early software, these things get fixed pretty quickly.
Getting an API Key
On first launch it asks for an API key, and it's not super clear which API key it wants (there's a configure later option). What we'll do is get a DeepSeek API key from their platform. Go to the DeepSeek platform, create an account, then API keys, create a new key, and copy the value. It won't be visible again, so make sure you capture it.
It's worth noting this sends your messages to DeepSeek's API platform, it's not running on your local computer. For many of you that's fine, but I wanted to call it out since local models are an option later in this lesson, and in that situation everything stays on your machine.
The very first prompt you send will probably give you an error saying you don't have any credits. Go back in to the platform, top up, and make a payment. This is not a subscription like you might get with ChatGPT or Claude, it's very similar to the OpenAI or Anthropic API platforms where you pay for credits as you go. I just put in $2 to get something going, and if you want to keep experimenting cheap you can use a cheaper model or off-peak rates (running things at certain times of the day). Once you have credits you can go to usage and see the cost as you go.
Setting up a Workspace
Next it has you select a workspace. This is just a directory on your computer that you'll be working from. You can create a dedicated folder for following along, I made one called DSH and chose that.
First Prompt
Now write whatever message you want. This is where you'll discover the first bug: for me, only the first character of my message was showing in the prompt box. It still picked up the full message, but I found it works a whole lot better in Safari, so I switched over and the prompt window stopped doing weird things.
I do like the way it shows the steps of a response:
- Context injection, which sounds a little scary but is just the context for the chat: the system prompt, any rules, basically the stage-setting for the conversation
- The skill catalog, which describes how to discover skills (empty for us so far)
- The think, the pre-message before the actual response
- Then the response itself
Important Config
Before the fun stuff, a few settings worth understanding.
First, access levels: read only, workspace write, or full access. Read only is what it sounds like. The dif between workspace write and full access is basically the ability to read and write outside of the workspace folder you opened. If I wanted it working with files outside this folder, I'd change it to full access.
Next, the model and effort. The default model is flash, a good one to get started with, and you can go pro if you're doing something heavier. Effort is either high or max, which is kinda funny, there's no option for low effort. We'll do high.
The other major setting shows up when you create a new session: the mode. There's standard mode, code mode, minimal mode, and creator mode. To keep things simple you can start off with standard mode, and that's what we'll use.
Code mode is pretty interesting though. It basically takes what would be a bunch of back and forth executions in standard mode and writes it as a single TypeScript program that can run as one file. You'd probably go for this option if you're doing something very repetitive across multiple files, condensing all of those round trips in to a single executable. Haven't tried that out yet, so I'm curious to see how it goes.
Minimal mode is a two tool coding agent with persistent bash and a string replace editor. Literally that's all it is, no web search or any kind of fancy features. I'm not entirely sure when we would want that, but you at least know it's there if someone's talking about it. And creator mode is like a layer up, for working on the infrastructure itself, so plugins and that kind of thing. It might come up later if I'm working on my actual workflows and not just some specific code files.
Initialize our Project
Right now we're in an empty workspace. What you'll typically do is create the git files to track changes, a .gitignore for stuff you don't want in the repository, and an AGENTS.md, basically the equivalent of a CLAUDE.md if you're coming from Claude. It describes the project and the things the agent should or should not do. It doesn't enforce anything, it just means the agent doesn't come in blind every time it starts working on your project.
So I just said:
create an agents md
Very vague, but it came up with a basic outline with a bunch of to-dos and slots to fill in as we go. I opened Visual Studio Code alongside so I could follow the file changes.
💡 Tip[!tip]
DeepSeek Harness can read aCLAUDE.md. So if you're coming from another project and want to test DeepSeek on it, it should pick up all of your existing instructions and execute pretty similarly.
Creating a Vault
We're going to create a folder called vault, and inside of it a spec.md. You can structure the vault however you want. I'm keeping it to a single spec for this example project, but on a complex project I might split it up: a file for auth, one for data, security, the different interfaces or sections of the app.
Then what I'd recommend is getting Obsidian. You can absolutely work in code, right-click a markdown file and open preview, split the panes, that works. I just think Obsidian gives a better experience. Open vault, open folder as vault, select our vault folder, and now you can edit the spec in line with a nice preview.
I started the spec with an author note section where I define what I want, and then the LLM can build out the spec from it. If you're just getting started you don't have to use a spec, but I think it gets much better results, because you can work on the spec almost like a separate thing: read through it, make sure it's what you want, then let the agent go do the thing. You don't have to check in with it every two seconds and direct it as it goes.
The project itself is really not the focus of this video, so it's a simple one: an app that displays buttons for our favorite websites in the browser, click one and it launches in a new tab. Kind of a visual homepage dashboard.
I also wanted a README to describe the project (that's different from everything we've created so far, it's what shows up on the GitHub homepage). So the prompt was along the lines of:
Create a readme describing the project. Create a repo and add our vault, the empty spec, the agents.md, and the readme.
It went through, created files, committed, and then asked a question about the hidden .obsidian directory it did not commit, offering to add it to the .gitignore.
At this point you should be able to go back to the platform and see your usage. You can toggle to today and even filter by API key. I'd spent less than a penny across 11 API requests.
Creating Skills
Skills are basically a way to package up certain behavior in to a keyword we can invoke whenever we need. If you do something very often, create it as a skill with steps the AI follows. A simple one to start with is a skill to commit your files. Yea, I know it's pretty easy to commit files on your own, but we can tie in any checks we need and how we want the commit message structured, ultimately saving time on something very repetitive. Here's the prompt I used:
Create a skill that will make a commit. Do not share attribution or mention AI, deepseek, etc. Keep a concise bulleted list for the message. Check quickly for anything that shouldn't be committed, but please assume default behavior of committing all working files, not just the ones you've touched. The goal is an empty working directory. Do not push changes or deploy anything.
I said "quickly" because it doesn't need a super thorough check on file sizes and types, and I don't want committing to be an elaborate process. It creates the skill and brings it in live, it appears in the session skill catalog immediately. For me the file landed inside the repo in an agents skills folder, just a markdown file that travels with the project.
I like to have the AI create the skill rather than writing it myself, it's pretty thorough: a description, a when-to-use, the numbered steps, some rules at the end. Probably better than I would have done. And skills aren't really anything fancy, these could just be MD files in our vault, because all it does is bring the skill's text in to context.
Deterministic Behavior
If you look at the generated skill, it does a "quick sanity check" for anything clearly unsafe, secrets, huge binaries, and so forth. But most likely it's just reading and interpreting, no formal checks. That's okay for some things, but for many things you'll want an actual script execution so the results are predictable and we're not getting different results for different runs.
Something that gives the same output for the same input is said to be deterministic, and anything that's a nice boolean yes or no is a perfect chance to use a deterministic check. The skill as generated was too much English, not enough code. Fixing that was one message:
Please convert to deterministic script
It thought for quite a while on this one and made a lot of changes. It removed model judgment from deciding what's safe and created a check-commit-safety.sh script: checks for secrets, a deny list, a large file check at 10 megabytes.
So let's test it. I created a .env with password=secretpassword in it and asked for a commit:
I just added a .env, confirm this would be added to a .gitignore on the trigger
It caught it, and asked me to confirm adding it to the .gitignore, which I did. That's an example of creating predictable outcomes from your AI instead of always trusting it to follow the words you tell it. As you've probably experienced, that doesn't always work.
Permissions and Plugins
If you've come from Claude Code, it asks permission for every single thing, which is really annoying, and the fixes there are adding things to your permissions, using auto mode (classifies safe vs dangerous), or dangerously skipping all permissions. That's the Claude world.
Within DeepSeek Harness it's different: it already has permission to do everything inside the workspace without asking. That's nice because you're productive right from the start, but there are definitely risks. Yes, it blocks execution outside the folder, but what about a CLI you can access from anywhere? For example:
use GitHub CLI to get my GitHub username
It just ran that bash without complaining or blocking. So there's more risk here than with something that blocks every execution.
The best protection is removing anything you don't want it able to touch. If you don't want it accessing your GitHub CLI, remove the GitHub CLI. If you don't want it touching your cloud provider CLI, remove that too, and same for databases, remove those connection strings from your local system so there's no way for it to even get that information. If you can't do it yourself, then your LLM can't do it for you. That can be a pain if those are tools you actively use, so the other route is running the whole thing in a container, an isolated environment that can't touch your primary system. Those are two different paths you can explore more on your own. Either way, just don't have access to your production database on your system, don't even make that damage possible.
On top of that, we can set explicit deny rules. These are not foolproof, see them as a way to guide the LLM and prevent it from doing something stupid on accident, if it's maliciously trying to achieve some goal it might bypass whatever you're blocking. As always, the easiest way is to ask the agent to set it up:
create a hook that will prevent you from executing git reset or any destructive behaviors to our repo
Whenever I create these rules I adjust them as I go, if they get too restrictive and constantly annoy me or prevent me from progressing on something, I loosen them up. Just start with something so you have some boundaries and adjust as you need.
A couple of interesting things happened here. First, it started trying to create a git shim that would prevent certain commands, not what I wanted. I don't believe DeepSeek Harness has the same formal hook structure Claude Code has, but it does have the ability to guard tool execution. Second, we got our first approval warning, because the change goes outside the workspace: it wrote in to a DSH folder in my home directory. It created this as a plugin wired in to my live profile, added instructions to AGENTS.md, and said it needs restarted before taking effect.
This is a good spot for clarifying questions, which I'd put in the README for anyone setting up the project:
what specifically was created outside of the workspace and what is created inside. If I switch computers, what needs set up?
The plugin lives outside, everything else travels with the repo. I committed, restarted the server, made a quick test change, then asked for a git reset --hard, and it came back with a bash blocked message from the protect hook. So it did work.
Then you can expand it with anything else you don't want possible:
Allow access to local DB only through docker psql and a direct psql is blocked
That makes sure it's not touching any of the Postgres databases on my system, only executing through Docker, and I only use Docker containers for data I don't care about. I also had it rename the plugin to a general command guard instead of the git-specific name, since one file should do all the blocking.
Create a Detailed Spec
Now the spec. I wrote mine out in Obsidian, roughly this:
- Database: Postgres container, access through
docker psqlonly - Goal: list out favorite sites with a nice icon, like a grid of squares
- CRUD: ability to add new favorites, edit title, description, and photo (default photo, so not required)
- A square at the end with a plus to add a new bookmark in a modal
- Single page app, mobile first: two bookmarks per row on small devices, maybe four to six on desktop
- Sections, with drag and drop from one section to another
- Button to open all sites from a section as new tabs
- Dark mode, please
- Extract any pure logic in to functions we can easily test, keep visual components as dumb as possible
- Spec will have two checkboxes per capability: one for implementation, one for a separate verifier's check
- Subagents: a verifier, plus a mobile verifier using Chromium to confirm visuals and UX
If I was building a really thorough subagent orchestration I'd go in to much more detail on what each agent does, and I'd have the AI help define them, which is exactly what we do next:
Look at the spec now. Please refine the sub agents. Keep it simple. Commit first. First evaluate anything we need that is missing. Don't write out the full spec quite yet.
It read the spec and came back with clarifying questions. The verifier it proposed runs the pure function unit tests, boots the API and checks every endpoint contract, checks database state directly via docker exec psql, and reports pass or fail. You could create more elaborate integration tests, but I'm fine with that for now. The UI verifier looks at the thing and makes sure it looks like a thing, and the main agent spawns both and triages their reports.
It also asked about the stack (I went with its recommended route), whether images should be uploads or URLs (URLs, keeping it simple), and how drag and drop should be implemented. Then it listed its assumptions, which is your chance to interrupt. I changed one: put Postgres on 5436 so it doesn't conflict with anything else I have running.
One more instruction I added, because I was worried about it improvising:
Don't do complex workarounds. If you're missing playwright, for example, don't just ignore it. Just install what you need, so we know the result is good.
Then I had it write the full spec and be as thorough as possible, thorough enough that general subagents could implement it. You could even use cheaper agents for that. This is a common thing I'll do: a more expensive model for the conversation, the spec, and the planning, then delegate the work to cheaper agents, because their output is easily verified against the spec.
Basically, spend a lot of time on the spec because it's going to make your life a whole lot easier.
DeepSeek Harness Subagents
The way subagents work in DeepSeek Harness is through a subagent tool. You can see it with something silly:
create five sub agents that all have to wait 60 seconds
You'll see the tool called five times, the subagents run in the background, and you can click in to any one of them to see its input and what it's doing. Each one has its own token usage, so there is a cost. But there's also a lot of benefit: your main chat keeps a much cleaner context window, focused on what it's focusing on, which probably gets better results using fewer tokens. So it costs, but it also saves you, if that makes any sense at all.
When a subagent finishes, it reports back to the invoker, the main agent.
Reviewing our Spec
The written spec came back with all the technology, prerequisites, the repository structure, the env, a Docker compose for the database, the commands needed, the data model from Prisma, all the API endpoints (not too many of them), a response shape, and front-end behavior, the actual action items a user can do, which is more what I was thinking of with a spec. This is doing a lot.
It also called out concerns before starting, specifically opening all tabs from a section (browsers block that) and favicon retrieval. Worth reading those and updating the spec if you want different behavior. Then:
commit then implement with sub agents
While it ran I checked usage, still had about $1.58 left. So I let it go and moved on to other models.
Working with other Models
Within settings you can go to models, and you can add a provider or a custom provider. There's a ton of options in the provider list. I went with Anthropic, created an API key over on the Anthropic side (named it DSH so I know what it's for), and pasted it in.
Now in a new session you can drop down and switch the model over to any of the Claude models. I don't know why 4.5 was showing as the latest when Opus 5 is right there, but I said hello, got a response, and watched a couple cents disappear from my Claude credits. There's a cost to any conversation since it reads the AGENTS.md and everything else, plus Opus is a more expensive model.
Local Models
We're not limited to paid models. For local models we'll use Ollama, which gives you a way to run models from your own computer. On Mac:
brew install ollama
brew services start ollama
(on Windows, just install it from the web page). Now in a browser visit localhost:11434/v1/models and you'll get a list of the models available to you.
There's a ton of models you can pull, the full list is on ollama.com. I searched for Qwen, a pretty popular one, and there's a bunch of different parameter sizes. If you're on a weaker system you might want to go for some of the smaller ones. The flagship Qwen right now is very large, 18 GB, and requires a lot of memory, so probably not recommended for most if you're just using it for daily use, but that's what I went with, plus a regular Qwen 3 which is only about 5 GB:
ollama pull qwen3.8:27b
ollama pull qwen3
Then within DeepSeek Harness, go to models and add a custom provider:
- Name it whatever, I said ollama
- Base URL is that same localhost URL without the
/modelsat the end:http://localhost:11434/v1 - OpenAI completions is fine for the API format
- Leave the API key empty
- Add a model
A couple of gotchas I hit:
- It complained about no API key for the provider, even though Ollama doesn't need one. Just edit the provider and put in a placeholder, I put an
x. - I got a 404 on the model.
ollama listin the terminal shows both names and IDs, and I'd grabbed the ID. It actually wants the name, so replace it with the name.
After that, I asked it to describe the repo, and it was working, but taking so freaking long that I eventually stopped it and gave Qwen 3 something simpler, 5 + 5. After a minute and 14 seconds it was able to conclude that 5 + 5 is 10. So yea, probably not how I would do agentic coding. But if you had some ongoing task to run overnight, a local model might do just fine. An example that comes to mind: generating embeddings for data you want to use for RAG. Kick it off overnight and you don't sit waiting on the result, and it costs nothing.
Different Provider Subagents
Back in the main chat, a quick experiment:
Create two sub agents both waiting 1 minute. One using opus, one using qwen 3.
It recommended a workflow tool with model overrides, which lets you pin a child agent to a specific LLM. And it worked, one subagent under Opus, one under Qwen, both just waiting and doing nothing, but you get the idea. Running subagents across different models from different providers is a pretty interesting idea. That's something I might need to explore in a dedicated lesson, I don't think I can give it the full attention it needs right here.
Project Review
Back to our original session: the favorite websites app is built, verified, and committed. The full spec, build, verify pipeline ran end to end as a single long-running autonomous run with background subagents, and it reported what was done, how it was verified, and the concrete results.
So let's use it. I added a site, and it pulled the most ugly favicon on planet Earth, so I edited it and pasted an image URL instead, a whole lot better (remember, we chose URLs over uploads). Added my YouTube channel. Created a news section and dragged a bookmark over, the drag and drop is a little wonky, that's something I'd get some dedicated back and forth with the agents on, but for a first run this ain't too bad. The light mode, dark mode toggle works. The open-all button opened one tab instead of both, which was one of the concerns it flagged before we even started, so I'm not surprised. And everything persists across a refresh since it's all in our local database. Pretty neat.
That's your introduction to DeepSeek Harness. It's a platform designed to be driven a lot by plugins, and there are already thousands of them, which is crazy considering how new the software is. This is literally a never-ending topic, so let me know if there's anything specific you'd like covered in an upcoming lesson.