Port an n8n flow into a Widget
You have an n8n flow that does one job. It takes a file or some values, does its work, and returns an answer. This Guide moves that job into a Python project and publishes it on Abyss as a Widget. Then people run it from a form in their browser, and your code calls it through the API.
A coding agent does the work with the abyss-widget skill. You make the decisions. Install the skill in your project:
npx skills add Abysshub/abysshub-sdk --skill abyss-widget -a claude-code-a names your agent. Give the agent your flow's export, and tell it to port the flow to Abyss. The skill takes it through the steps below, in this order. Each step says what the agent asks of you.
Check that your flow fits
A Widget works in runs. A run takes inputs, does one job and returns an output. It keeps nothing from one run to the next. Your flow fits when it does the same.
- •The trigger stays outside the Widget. A webhook, a form or a schedule that gives one item to the flow becomes a caller of the Widget.
- •A loop over many items becomes one run for each item, or one run on a file that holds them all.
- •Abyss runs Python only. The agent writes each Code node and each expression again in Python.
- •A node that calls a service becomes a call to that service's HTTP API or its Python library.
Abyss is the wrong tool when the work of the flow is to wait and watch. Do not port these:
- •a sync, a monitor or an inbox rule, which reacts to events;
- •a bot or a server, which must stay up between requests;
- •an app with accounts or pages of its own;
- •a flow that needs a person to sign in on every run.
For such a flow, the agent tells you why and stops. This step ends when you can say in one sentence what one run takes and what it returns.
Collect real cases
A case is one real use of the flow: the inputs it got and the output it returned. The agent checks the Widget against your cases, so take them from real work.
- •Give the agent a few ordinary cases. Choose cases that show each kind of input you really get.
- •Give it one case that must fail, for example the wrong kind of file.
- •Take the cases from n8n's execution history when you can. It holds the inputs and the outputs of real runs.
- •When you have no record, the agent runs the flow's logic on the inputs, or works out the output. It writes down how, and you confirm it.
The agent adds its own cases where yours leave a gap, and marks them as made up. The cases stay in a folder beside the Widget's folder, never in it. So your client's data never goes into the upload.
Confirm the Done List
The Done List says what the Widget must do. The agent writes it before it writes any code. It holds:
- •one sentence on what one run takes and what it returns;
- •each input of the flow, and the Field it becomes (see Field types);
- •each output of the flow, and the Result key or the file it becomes (see Outputs);
- •each odd behaviour of the flow that the Widget keeps;
- •what the flow sends, and the secrets it needs (the next two steps);
- •each case, what must hold for it, and what may vary.
"Must hold" is what makes an output correct: a total, a value that must be there, a file and its type. "May vary" is what can change and stay correct: the wording, the order, the phrasing of an AI model.
The agent also finds what Abyss asks and n8n did not. A run that writes no output fails on Abyss, so the Done List says what the Widget writes instead. Your largest input must fit the Run limits.
Read the whole list, then correct it or confirm it. Tell the agent too whether to put the Widget on Abyss, or only to prepare its folder. The agent writes no code before you confirm.
Decide what the flow sends
Many flows end with a send: an email, a Slack message, a row in a CRM. By default the Widget does not send. It returns what the flow would send, and the caller sends it.
- •The subject and the body of an email come back in the Result.
- •A CRM row or an accounting entry comes back as a file.
- •A call that does the work itself stays in the Widget, for example a model that reads an invoice. The Done List names it, so you know where your data goes.
The Widget sends only when the send is the whole job of the flow. Then a case that sends runs only against a test account that you supply, and only when you agree.
Keep the secrets out of the code
A secret is a key or a password that the flow uses, for example an OpenAI key. The Done List names each secret by the name of its variable.
- •Write each secret into
.envin the Widget's folder yourself, oneNAME=valueon each line. - •The agent never reads, prints or writes the value of a secret.
- •A case that needs a secret you did not supply does not run. The agent marks it "not run", not "failed".
- •A flow that needs a person to sign in on every run ports only when a long-lived token can replace the sign-in. That token is a secret too.
The upload keeps .env out of the Widget's files and gives its variables to every run. What isn't uploaded and Environment variables tell how.
Build the Widget
The agent now writes the Widget's folder from the Done List: run.py, requirements.txt and interface.json (see The project).
- •It keeps the logic of the flow. It changes only what Abyss needs: where the inputs come from, where the outputs go, and where the secrets come from.
- •It copies the prompts, the formulas and the rules of the flow word for word. An improvement comes later, after the Check.
- •A Code node keeps its JavaScript behaviour, not only its steps. For example,
parseFloat("1,742.16")is1in JavaScript. The agent writes small helpers for such behaviour and tests them. - •It pins each package in
requirements.txtand checks the pins withpip-audit.
When you ask for a change after you confirm the Done List, the agent records it in the Done List as yours. Then it runs every case again.
Run the Check on your machine
The Check runs every case and compares the Widget's outputs with the flow's. The agent runs it on your machine first, the way Abyss runs a Widget. Then it judges each case against the Done List:
- •passed: the run ended without a fault, each output came out, and each answers the same question as the flow's output. The words may differ.
- •failed: one of these is not true. The agent says which, and fixes the Widget.
- •not run: a secret is missing, or you kept the case from running.
The agent fixes the Widget and runs the cases again until each case that can run has passed. Then it shows you the failures it fixed, and some passes beside the flow's outputs. Read them, and say whether you agree. Nothing goes to Abyss before you agree.
Run the Check on Abyss
Skip this step when you chose the folder only. Otherwise the Check runs once more on Abyss, so it covers the build and the upload too.
- •Press Publish in the navbar, and drag the Widget's folder into the uploader.
- •Press Test Run with the inputs of one case. Then publish the Widget as PRIVATE. Test, publish, price says what publishing needs.
- •In your Cave, create an API key with a small Monthly Spend Cap. Write it yourself into
.envin the cases' folder,port/: never into the chat, and never into the Widget's.env. - •Give the agent the address of the Widget's page.
The agent runs the cases that you allow on Abyss, through the API, and judges them as before. Each of these runs stays in your account. So allow only the cases whose data may stay there.
Hand it over
At the end, the agent tells you:
- •what the Widget does, in one sentence, and its Fields;
- •how many cases passed, failed or did not run, on your machine and on Abyss;
- •how other people reach the Widget: its Private Link, or its page when you make it public (see How people run your Widget);
- •what is left to you.
The claim is that the Widget works and makes sense on these cases. It is checked on your real cases. Nobody claims that it equals the flow.
What is left to you is often the trigger. The webhook or the schedule that started the flow now calls the Widget, and your code calls it with the abysshub library (see Call Abyss from your code). The sends that the Widget returns are yours to make too.