Posted on

Interim cover?

Thoughts of the Fractional ChiefIs it really the right solution for you?

Imagine this:
Your CTO (or another C-level leader) leaves, and overnight you’re in a management vacuum.

The teams start to struggle, because there is no overall technical direction in place, and you personally do not have the capacity or ability to fill the gap, especially not covering the tech. 

The team still has work to deliver. Someone still has to make decisions. Vendors still need answers. Security and operational issues don’t pause. The board still expects updates. And yet the person who used to hold all of that context has walked out the door.

So you do what most companies do: you start looking for an interim.

But what if the “interim” model isn’t actually the best fit?

The gap isn’t always full-time

In a lot of companies, the real problem isn’t that you need a permanent replacement immediately.
The real problem is that you need experienced decision-making and leadership continuity while you stabilise things.

That can mean:

  • keeping delivery moving without a new exec in place
  • making sure priorities don’t drift
  • reducing operational risk
  • helping the team stay focused and calm
  • creating a plan for the next 30–90 days
  • supporting a hiring process properly, instead of rushing it

And in many cases, you don’t need that support 40–60 hours a week.
You need it consistently, but not constantly.

A fractional executive fills the vacuum differently

A fractional portfolio executive is a senior leader who steps in on a part-time basis and takes ownership of the “executive-shaped” work that still needs doing.

They’re not a consultant who writes a report and disappears. They’re also not staff augmentation.
They’re there to:

  • lead decisions and create clarity
  • unblock execution
  • work with the team in the real world (not in theory)
  • support stakeholders, investors, and the board
  • stabilise operations while you figure out the long-term plan

The key difference is that it’s structured as ongoing leadership support, with a cadence, not a full-time role by default.

When fractional makes sense

Fractional leadership is often the right move when:

  • you need continuity after a departure
  • you’re hiring, but don’t want to rush the wrong person in
  • the team needs direction and alignment more than “more hands”
  • you’re in a regulated context and can’t afford drift
  • reliability is shaky and incidents are starting to distract the organisation
  • delivery is happening, but it’s not predictable
  • your business is growing, and your current operating model is getting stretched

It also serves well when you need support across multiple areas (technology, operations, security, sometimes HR), but it is not enough to justify separate full-time hires.

What fractional engagement can look like in practice

This isn’t about parachuting in and trying to “run the show”. The goal is to stabilise, set direction, and make the team stronger.

A typical engagement might involve:

  • an initial discovery phase (what’s happening, what’s stuck, what’s risky)
  • a clear 30/60/90-day plan of action to get unstuck and get things flowing.
  • a simple weekly cadence with leadership and team touchpoints
  • decision support for architecture, delivery, hiring, and risk
  • help creating an operating rhythm: ownership, metrics, and follow-through
  • clean handover when the time is right — either to a new hire or an internal leader

That last part matters. Fractional should leave the company in a better place than it found it, not dependent on an external person.

What it’s not

It’s worth being clear about what this is not:

  • It’s not paying for a permanent C-level seat without commitment.
  • It’s not a slide deck and a set of recommendations.
  • It’s not a ticket-taking role or “extra developer capacity”.
  • It’s not taking ownership away from founders or the team.

Fractional leadership works best when it supports decision-making and execution, while ownership stays where it belongs.

A good question to ask yourself:

If you’re in that vacuum right now, or you can see it coming, do you need the experienced guidance, continuity and a clear plan while you stabilise now, and decide what to do next, giving you proper time to find the right long-term solution, without pressure? 

If you find yourself in this very position, let’s talk!
Book a meeting with us – click the link!

Posted on

Friday Tip – AWS ECS container IP’s?

Have you ever had the problem where you quickly need to know what IP does a container use when running in the ECS?

Well, here’s one for that… 

  • Upload to your cloudshell. 
  • run chmod +x ecs2ip.sh
  • then, execute such as ./ecs2ip.sh dev or ./ecs2ip.sh dev 'container-name'
#!/bin/bash

CLUSTER="$1"
SEARCH="$2"

if [ -z "$CLUSTER" ] 
then
    echo "Usage: $0  ['optional search phrase']"
    exit 1
fi

# Change to match your region, or add as an argument... 
REGION=eu-west-1

TASK_ARNS=$(aws ecs list-tasks \
  --cluster "$CLUSTER" \
  --desired-status RUNNING \
  --region "$REGION" \
  --query 'taskArns' \
  --output text)

[ -z "$TASK_ARNS" ] && echo "No running tasks found" && exit 0

printf '%s\n' $TASK_ARNS | xargs -n100 | while read -r CHUNK; do
  aws ecs describe-tasks \
    --cluster "$CLUSTER" \
    --region "$REGION" \
    --tasks $CHUNK \
    --output json \
  | jq -r '
      .tasks[] as $t
      | (
          $t.attachments[]
          | select(.type=="ElasticNetworkInterface")
          | .details[]
          | select(.name=="privateIPv4Address")
          | .value
        ) as $ip
      | $t.containers[].name as $c
      | "container=\($c) ip=\($ip) taskArn=\($t.taskArn)"
    '
done 2>&1 > /tmp/ecslist.txt 

if [ -z "$SEARCH" ]  
then
   cat /tmp/ecslist.txt 
else
   grep "$SEARCH" /tmp/ecslist.txt 
fi

rm /tmp/ecslist.txt

The output would look something like: 

[cloudshell-user@ip-*****~]$ ./ecs2ip.sh dev container-name
container=container-name ip=10.0.0.1 taskArn=arn:aws:ecs:eu-west-1:**************:task/dev/****…***
container=container-name ip=10.0.0.2 taskArn=arn:aws:ecs:eu-west-1:**************:task/dev/****…***

Njoy!

Posted on

A Dev Suppoort tool for GitHub

Every now and then, one may wish to have had a simple script to check out or
update all the github repos you have, at once, using a single command. 

This can be for the reason of backups, or simply, check out new ones that you don’t have etc,
or, keeping a local up-to-date copy of everything. 

Well, I wrote a similar little script some time back for BitBucket.
(http://emberlabs.tech/2023/05/08/easily-mirror-a-bitbucket-repo/)

This should work just fine on pretty much any Linux or Mac install (or similar with a bash). 

Nuf of the talk! Show me the code!! =D

#!/bin/bash
# GH Mass checkout. 
# V 1.0 - 2025-11-23 Spruce
# Prerequisites: curl and jq
# Place your GH PAT in ~/.gitpat (contents / read-only needed)
# Relies on SSH for cloning/pull, add your public key to GH. 

ORG="[Your ORG name here]"
PAT="[Your GH PAT]"
CDIR="$(pwd)"

if [ "${PAT}" == "" ] 
then
    if [ -e ~/.gitpat ] 
    then 
        PAT="$(grep github ~/.gitpat | head -1)"
    else
        echo "No PAT available."
		echo "Create a PAT (Profile -> Settings -> Developer settings -> PAT"
		echo "Select fine-grained,  account/org, and all repos, then select contents with read-only."
        exit 1
    fi
fi

function GetRepoLists {
    echo ""
    echo -n "Updating the repolists : "  
    rm -f repolist.*
    for page in $(seq 1 20) ; do
        echo -n "${page} "
        curl -s \
            -H "Accept: application/vnd.github+json" \
            -H "X-GitHub-Api-Version: 2022-11-28" \
            -H "Authorization: Bearer ${PAT}" \
            "https://api.github.com/orgs/${ORG}/repos?per_page=100&page=${page}" \
            | jq -r '.[].ssh_url' > repolist.${page}
        if [ ! -s "repolist.${page}" ]
        then
            rm -f "repolist.${page}"
            break
        fi
    done
    echo ""

    cat repolist.* > repolist
    rm -f repolist.*
}


function ClonePull {
    mkdir -p ${ORG}

    while IFS= read -r URL; do
        repo="${URL##*/}"
        repobase="${repo%.git}"
        if [ -e "${ORG}/${repobase}" ]
        then
            echo "Updating ${ORG}/${repobase}" 
            cd ${ORG}/${repobase}
            git pull
            cd ${CDIR}
        else
            echo "Cloning  ${URL}"
            cd ${ORG} 
            git clone ${URL}
        fi
    done < "./repolist"
}

function GitExec {
	GITCMD="$1"
	cd ${ORG}
	for repo in *
	do
		echo "Executing ${GITCMD} in ${ORG}/${repo}" 
		cd ${CDIR}/${ORG}/${repo}
		git ${GITCMD}
		cd ${CDIR}
    done 
}

# --- Actions -------------------------------------------------------

case "$1" in
    full)
        GetRepoLists
        ClonePull
        ;;
    pull)
        GitExec "pull"
        ;;
    fetch)
        GitExec "fetch"
        ;;
    *)
        echo "Usage:"
        echo " "
	echo "       full      Update existing and clone new repos."
        echo "       fetch     Execute a fetch on all existing repos."
	echo "       pull      Execute a pull on all existing repos."
    ;; 
esac

Njoy!!

Posted on

Pink October Talk @ Glitnor Group

Chris Sprucefield
Pink October talk at Glitnor Group.

Breast cancer…

There’s four dreaded words that you as a guy don’t ever want to hear, and no woman ever want to say –
“I found a lump”.

To me, us, this happened quite some time ago, end of 90’s, and I’m happily remarried since, but my story goes a long way, and it still goes to show how fast it can happen and develop like the lightning strike out of nowhere.

While the research has come quite some way, there’s still no cure, and it’s an illness that leaves no one untouched. It’s evil. It affects everyone involved, in ways you can not imagine, until it happens, and even then, you end up being stumped and lost, even as a “bystander”.

It started with a lump, she got treatment, and then it looked all good and well for some time. We moved countries, and one day, she said – I can’t hear on my left ear. Hospital, and it had returned, 4 years later, now, metastatic, and from there, it was all downhill, and she eventually passed away.

Luckily, today, this will not be the case for everyone, as treatments has gotten way better, but the treatments is not all.
There’s many more aspects to it than just treatments…

One of the worst part for us, was long time friends disappearing, because they “could not deal with cancer”, or hospitals. They just tried to find any excuse to bail out, with the exception of a very few that stuck around. If you are a true friend of someone, don’t be that person and take the bailout card – be the one that cares, even if just in the small things…

Here’s some of what you can do, even if you don’t have much time or resources, that will be gold dust to victims of cancer (in general)

  • Please, Warn the person going for the chemo, not to eat the usual things they like or love afterwards, avoid them for the time being, or you may end up not being able to eat them afterwards, as chemo can / will play tricks with your mind… nobody tells you this, and we wished someone had…
  • They got kids?
    Apart from just life – just like you, we are all busy, but they also have to deal with the effects of cancer and treatments, apart from the existential crisis they inevitably go through, and it is wearing people down. Offer their kid(s) the occasional sleepover, or just to take them off them even for a day/evening.
    They need adult time to cope, or even just peace and quiet. You have no idea what the value of such a small gesture is or may be…
  • Chemo?
    They just got back… They still need to eat and so on… Going to the shop?
    Ask them – I’m going shopping, you need any top-up stuff while i’m there?
    That top-up shop delivered, may be the difference between having to do a shop the day after the chemo, or 2 days later when you feel better and you can actually cope with it, because, we are all people, and we forget things, until we need it…
  • Getting to / from the hospital? If you can, take them there and pick up. Get a paper “flight sickness bag”, just in case. Just keep it in the car. you know why…
    Take that one worry out of their life if you can, they have enough existential stuff on their minds already, and that is gold, and they know they are safe with you…

The practical little things…

Sometimes, people being people, things can get too much for anyone, and if they cuss you out, having a particularly bad day, don’t take it personally – they are likely just exhausted and need to vent, and you just happen to be in the firing line for just being their trusted friend, because they feel comfortable and safe around you, so take it, just listen and don’t let it get to you.
Really – let it go in one ear and out the other… I know it’s hard, but you are the true friend, and for good reason.
They will be embarrassed enough afterwards about what happened, but be there the next time… the true friend you are.

Everyone has ups and downs. They just have some more of it, right now – the downs, and the feelng of world being against them.

Be the brave one for them – they need you and your strength as their guidance, and your presence as the anchor to reality.
Think about it – It’s not really hard things, it’s not big things, even small things count big time, but just being around, for a call, for a coffee etc.

It’s quality of life, the sense of normality that brings hope and future back into the picture. You just being you as usual, and most importantly, being there, counts.Now, you can do the above, and you can also donate to research to make this problem eventually become what we all want – extinct.Take care out there!

#PinkOctober #BreastCanscerSpouse #BreastCancer #BreastCancerAwareness

Posted on

Tinypng script

Using the service from https://tinypng.com makes it easy to mass-shrink your PNG images to more palatable sizes, and it comes with a neat 500 free use transcodes per month, and it’s quite cheap after that.

Here’s a little script to help you with the work a bit.

Prerequisites:
bash, jq and curl.

Save the file as “tinify” and do a chmod 755 tinify

Flags:
-k <key> = API key for tinypng.com – can be omitted if specified in the environment variable by export TINIFY_API ="<api_key>"
-f <file> = Filename to compress
-r = Replace the original file with the compressed file. If not specified, the output file will be named tiny-<filename>
-v = verbose output
-s = Show compression statistics (1 line per file)

#!/bin/env bash
# (C) EmberLabs / Chris Sprucefield 2023.
# License: CC BY.

key=''
file=''
r_flag=false
v_flag=false
s_flag=false
s_arg="-s"

if [ "${TINIFY_API}" != "" ]
then
    if [ "${v_flag}" == true ] ; then echo "Using API key from env." ; fi
    key="${TINIFY_API}"
fi

while getopts 'rk:f:vsh?' flag; do
case "${flag}" in
    r) r_flag=true ;;
    k) key="${OPTARG}" ;;
    f) file="${OPTARG}" ;;
    v) v_flag=true
       s_arg="" ;;
    s) s_flag=true ;;
    *)
        echo "<cmd> -? | -h This help text"
        echo " -r Replace the original file with tinified file."
        echo " -k <apikey> The API key for tinify (or from \$TINIFY_API environment variable if set)"
        echo " -f <filename> The filename to encode (and replace if -r is specified)"
        echo " -v Verbose output"
        echo " -s Show compression statistics"
        exit 1
        ;;
    esac
done

if [ "${v_flag}" == true ] ; then echo "Processing ${file}" ; fi
JSON="$(curl ${s_arg} --user "api:${key}" --data-binary "@${file}" -i https://api.tinify.com/shrink | tail -1)"
URL="$(echo "${JSON}" | jq '.output.url' | sed 's/\"//g')"
ISIZE="$(echo "${JSON}" | jq '.input.size')"
OSIZE="$(echo "${JSON}" | jq '.output.size')"
RATIO="$(echo "${JSON}" | jq '.output.ratio')"
W="$(echo "${JSON}" | jq '.output.width')"
H="$(echo "${JSON}" | jq '.output.height')"

if [ "${ISIZE}" == "${OSIZE}" ]
then
    if [ "${v_flag}" == true ] ; then echo "No compression on ${file} - skipped." ; fi
    exit 0
fi

if [ "${URL}" != "null" ]
then
    if [ "${v_flag}" == true ] ; then echo "Fetching ${URL}" ; fi
    curl ${s_arg} "${URL}" -o "tiny-${file}"

    if [ "${r_flag}" == true ]
    then
        if [ "${v_flag}" == true ] ; then echo "Replacing original file" ; fi
        mv -f "tiny-${file}" "${file}"
    fi
    if [ "${s_flag}" == true ]
    then
        printf "%-40s %5d x %-5d In: %8d Out: %8d Ratio: %2.5f\n" "${file}" "${W}" "${H}" "${ISIZE}" "${OSIZE}" "${RATIO}"
    fi
else
    echo "Invalid response. (incorrect API key?)"
    exit 1
fi