Waddle.Cli 0.4.4

dotnet tool install --global Waddle.Cli --version 0.4.4
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Waddle.Cli --version 0.4.4
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Waddle.Cli&version=0.4.4
                    
nuke :add-package Waddle.Cli --version 0.4.4
                    

Waddle: Penguins with packets 📦🐧

<img width="1282" height="283" alt="image" src="https://github.com/user-attachments/assets/3dce8a42-17ba-4ac5-aee7-70dbe36a5b39" />

Waddle is a tool that automates deploying your project to servers like nest. It can also be used to automate other kinds of client/server interaction. Think of it as little penguins waddling back and forth between your client and your server (or nest).

https://github.com/user-attachments/assets/4116d550-c0f4-4232-baba-508ac92ed45f

The video shows me using Waddle to deploy a Nextjs project. I added the text "Deployed using Waddle" which can be seen at the end of the video.

Table of Contents

Use of AI: I used Claude to help me with the Dockerfile for the test server.

Quick Start

Requirements: Docker, .NET SDK

If you just want to try the project temporarily follow these instructions in any directory:

# Clone the whole repository because it contains a test workflow
git clone https://github.com/Schlafhase/Waddle
cd Waddle
dotnet tool install -g Waddle.Cli
# Create and start docker container
./TestServer/start.sh

Now you can start playing around:

The credentials for the docker container are

  • Host: localhost
  • Username: root
  • Port: 2222
  • Password: Docker!
waddle init # Also add a nest (server) and fill out the credentials above
# Run test workflow
waddle Waddle.Cli/test

How to clean up

# Remove the docker container
docker rm -f waddle-test-server
# Uninstall the tool
dotnet uninstall -g Waddle.Cli
# Remove directory
cd ..
rm -rf ./Waddle/

Installation

Using dotnet tools

If you have the .NET SDK installed, you can install Waddle with this simple command:

dotnet tool install -g Waddle.Cli
On NixOS
environment.systemPackages = [
    # ...
    (buildDotnetGlobalTool {
      pname = "waddle";
      nugetName = "Waddle.Cli";
      version = "0.4.1";
      nugetHash = "sha256-tACHDgvmmXZNwDn7qgcv+iCle1X154HrekdV8KQ7jiQ=";
      dotnet-sdk = pkgs.dotnetCorePackages.sdk_10_0;
    })
];

Or with home manager:

home.packages = [
    # ...
    (buildDotnetGlobalTool {
      pname = "waddle";
      nugetName = "Waddle.Cli";
      version = "0.4.1";
      nugetHash = "sha256-tACHDgvmmXZNwDn7qgcv+iCle1X154HrekdV8KQ7jiQ=";
      dotnet-sdk = pkgs.dotnetCorePackages.sdk_10_0;
    })
];

Manual installation

The binary for Windows hasn't been tested yet

Grab the binary from the latest release (waddle for Linux and waddle.exe for Windows). Move the binary to a directory in your PATH. You should be ready to go now.

Usage

Go to your projects directory and run waddle init. After answering all questions, you should see waddle.yaml. You can check its content to confirm your configuration.

Creating workflows

To create a workflow, create a yaml file with the name of your workflow. Each workflow is a yaml sequence of actions (I call them penguins). Every penguin needs a name and some parameters depending on the type. Here is the list of all available penguins:

A good place to look for example usages of penguins is Waddle.Cli/test.yaml

Penguin Description Parameters
SendCompressedFolder Sends a folder as a tar archive and extracts it on the server. Requires tar to be installed on both the client and the server sendCompressed (string), destination (string)
ReceiveFile Downloads a single file from the server to a destination (file!) on the client receiveFile (string), destination (string)
SendFolder Uploads a folder to a destination (directory!) on the server sendFolder (string), destination (string)
ReceiveFolder Downloads a folder from the server to a destination (directory!) on the client receiveFolder (string), destination (string)
RunServerCommand Runs a command on the on the server via SSH serverCmd (string)
SendFile Uploads a single file to a destination (file!) on the server sendFile (string), destination (string)
RunCommand Runs a command on the client using the value of shell as shell or sh (Linux) or cmd.exe (Windows). shell must be something like ["sh", "-c"] (in yaml syntax of course). Specify variable to store the output in a variable. cmd (string), shell (List<string>), variable (string)
RunWorkflow Runs a workflow from a filepath or a list of penguins workflow (string), children (List<IPenguin>)
Throw Throws an error. Either ifTruthy or ifFalsy can be set to variable names to only throw if the variable has a falsy ("0", "false", "null", unset) or truthy (anything else) value (case-insensitive, whitespace will be trimmed) Error (string), ifTruthy (string), ifFalsy (string)

Defining parameters matching multiple penguins can lead to unexpected behaviour

Additional Parameters

In addition to the required parameters, each penguin can define these optional parameters:

  • ignoreError (bool): If true, the workflow will continue if this penguin fails
  • timeoutMs (int): Sets the timeout in milliseconds

Variables

Some penguins can export variables (currently only the RunCommandPenguin). These variables can be used in almost any string value by writing "${variableName}". Variable names can contain alpha-numeric characters and an underscore. If you still need to write out "${variableName}" for some reason, use two dollar signs to escape it: "$${variableName}".

Example

Here is the workflow I used in the demo video:

# deploy.yaml
- name: Build # RunCommand penguin
  cmd: npm run build
  shell: # Use custom shell (since sh is the default on Linux, this is redundant and just for demonstration)
    - sh
    - -c

- name: Remove unnecessary files from build # RunCommand penguin
  cmd: rm -rf ./.next/standalone/node_modules
  ignoreError: true

- name: Stop systemd service # RunServerCommand penguin
  serverCmd: systemctl stop --now devqed

- name: Copy files to Server # SendFolder penguin
  sendFolder: ./.next/standalone/
  destination: /home/Linus/Projects/qed/QED-Online/.next/standalone/

- name: Start systemd service # RunServerCommand penguin
  serverCmd: systemctl start --now devqed
  ignoreError: true

Running Workflows

Workflows will always use the directory they are defined in as CWD. This means that relative file paths will resolve relative to the yaml-file that defines the workflow. This also includes workflows imported via the workflow parameter.

The quick answer: waddle {workflow name}

The details:

You can run any workflow using waddle {workflow name}. For example, use waddle build to run the workflow specified in build.yaml or build.yml (You may also use .w.yaml and .w.yml to avoid conflicts with other tools). You may specify the file ending explicitly but you don't need to.

You can specify a default workflow in the config file waddle.yaml or using waddle init. Use the waddle command without any arguments to run the default workflow.

Full config specification

You can edit these in waddle.yaml

Extracted from WaddleConfig.cs

public WaddleServerConfig? Server;

public string? ClientOutputFileName;

public string? LogFileName;
public LogLevel LogLevel; // Trace | Debug | Information | Warning | Error | Critical

[YamlMember(Alias = "FinishedIcon")]
public string SuccessIcon;
public string WaitingIcon;
public string ErrorIcon;
public string IgnoredIcon;

[YamlMember(Alias = "NotActiveIcon")]
public string IdleIcon;

public required string DefaultWorkflow;
public List<string>? DefaultShell; // e.g. ["sh", "-c"]

public bool VerboseErrors;

Server config

Extracted from WaddleConfig.cs

public required string Host;
public int Port;
public required string Username;

public bool UsePassword;
public string? Keyfile;
public bool UseSshAgent;

public string? ServerOutputFileName;
public char DirectorySeparator = '/';

For developers

This project needs the .NET SDK to be installed. Run these commands to set up the codebase:

git clone https://github.com/Schlafhase/Waddle
cd Waddle
dotnet build

Test Server

This repository comes with a Dockerfile that can set up a server that runs SSH on it. Follow these instructions to set it up:

# cp ~/.ssh/id_ed25519.pub ./TestServer/id_ed25519.pub # Uncomment this if you want private key authentication
docker build -t ssh-container ./TestServer
docker create -p 2222:22 -t --name waddle-test-server ssh-container
docker start waddle-test-server

Then use these values in your waddle.yaml:

# ...
Host: localhost
Username: root
Port: 2222
# Keyfile: ~/.ssh/id_ed25519 # If you copied your public key before building the docker image
# UsePassword: true # If you didn't copy the public key
# ...

If you use password authentication, the password is Docker!

Project overview

  • Penguins: This project contains the implementations for every penguin
  • TestServer: Contains a Dockerfile to build a quick server for testing
  • Waddle.Cli: The Command-Line-Interface. Can be run with dotnet run
  • Waddle.Config: Everything yaml-related

How it works

The workflow parsed from the yaml parser gets converted to penguins using pattern-matching. There are patterns to check for required parameters of specific penguins. Every penguin imlements Penguins.IPenguin which ensures they have an async Execute method. That makes it easy to execute each penguin.

If you implement your own penguins, you'll likely want to inherit from Penguins.PenguinBase.

Waddle uses SSH and SFTP (SSH File Transfer Protocol) under the hood. Penguins that need client/server interaction will use these technologies.

Planned features

  • Unit tests (Implementing)
  • Move interpolation resolver to YamlPenguin level more more flexibility
  • Check fingerprint
  • Choose shell program (Implemented but not thoroughly tested)
  • Allow nested workflows (Implemented but not thoroughly tested)
  • Allow penguins to hide
  • Allow penguins to throw errors
  • Add SendCompressedFolderPenguin (Implemented but not thoroughly tested)
  • Add ReceiveCompressedFolderPenguin
  • Add client-only workflows (Implemented but not thoroughly tested)
  • Workflow variables (Implemented but not thoroughly tested)
  • waddle new command to add a workflow (not planned)
  • Run waddle workflows from the directory of the workflow to prevent unexpected behaviour (Implemented but not thoroughly tested)
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.4.4 116 7/23/2026
0.4.3 130 7/23/2026 0.4.3 is deprecated.
0.4.2 110 7/17/2026
0.4.1 117 7/17/2026
0.3.1 109 7/16/2026
0.3.0 122 7/16/2026